home *** CD-ROM | disk | FTP | other *** search
/ System Booster / System Booster.iso / Archives / GNU / GNUPLOTsrc.lha / set.c < prev    next >
C/C++ Source or Header  |  1996-01-22  |  82KB  |  2,925 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: set.c,v 1.29 1995/12/20 22:39:36 drd Exp $";
  3. #endif
  4.  
  5.  
  6. /* GNUPLOT - set.c */
  7. /*
  8.  * Copyright (C) 1986 - 1993   Thomas Williams, Colin Kelley
  9.  *
  10.  * Permission to use, copy, and distribute this software and its
  11.  * documentation for any purpose with or without fee is hereby granted, 
  12.  * provided that the above copyright notice appear in all copies and 
  13.  * that both that copyright notice and this permission notice appear 
  14.  * in supporting documentation.
  15.  *
  16.  * Permission to modify the software is granted, but not the right to
  17.  * distribute the modified code.  Modifications are to be distributed 
  18.  * as patches to released version.
  19.  *  
  20.  * This software is provided "as is" without express or implied warranty.
  21.  * 
  22.  *
  23.  * AUTHORS
  24.  * 
  25.  *   Original Software:
  26.  *     Thomas Williams,  Colin Kelley.
  27.  * 
  28.  *   Gnuplot 2.0 additions:
  29.  *       Russell Lang, Dave Kotz, John Campbell.
  30.  *
  31.  *   Gnuplot 3.0 additions:
  32.  *       Gershon Elber and many others.
  33.  *
  34.  * 19 September 1992  Lawrence Crowl  (crowl@cs.orst.edu)
  35.  * Added user-specified bases for log scaling.
  36.  * 
  37.  * There is a mailing list for gnuplot users. Note, however, that the
  38.  * newsgroup 
  39.  *    comp.graphics.gnuplot 
  40.  * is identical to the mailing list (they
  41.  * both carry the same set of messages). We prefer that you read the
  42.  * messages through that newsgroup, to subscribing to the mailing list.
  43.  * (If you can read that newsgroup, and are already on the mailing list,
  44.  * please send a message info-gnuplot-request@dartmouth.edu, asking to be
  45.  * removed from the mailing list.)
  46.  *
  47.  * The address for mailing to list members is
  48.  *       info-gnuplot@dartmouth.edu
  49.  * and for mailing administrative requests is 
  50.  *       info-gnuplot-request@dartmouth.edu
  51.  * The mailing list for bug reports is 
  52.  *       bug-gnuplot@dartmouth.edu
  53.  * The list of those interested in beta-test versions is
  54.  *       info-gnuplot-beta@dartmouth.edu
  55.  */
  56.  
  57. #include <math.h>
  58. #include "plot.h"
  59. #include "setshow.h"
  60. #include "national.h"
  61.  
  62. #define DEF_FORMAT   "%g"    /* default format for tic mark labels */
  63. #define SIGNIF (0.01)        /* less than one hundredth of a tic mark */
  64.  
  65. /*
  66.  * global variables to hold status of 'set' options
  67.  *
  68.  * IMPORTANT NOTE:
  69.  * ===============
  70.  * If you change the default values of one of the variables below, or if
  71.  * you add another global variable, make sure that the change you make is
  72.  * done in reset_command() as well (if that makes sense).
  73.  */
  74.  
  75. TBOOLEAN        autoscale_r    = DTRUE;
  76. TBOOLEAN        autoscale_t    = DTRUE;
  77. TBOOLEAN        autoscale_u    = DTRUE;
  78. TBOOLEAN        autoscale_v    = DTRUE;
  79. TBOOLEAN        autoscale_x    = DTRUE;
  80. TBOOLEAN        autoscale_y    = DTRUE;
  81. TBOOLEAN        autoscale_z    = DTRUE;
  82. TBOOLEAN        autoscale_x2    = DTRUE;
  83. TBOOLEAN        autoscale_y2    = DTRUE;
  84. TBOOLEAN        autoscale_lt    = DTRUE;
  85. TBOOLEAN        autoscale_lu    = DTRUE;
  86. TBOOLEAN        autoscale_lv    = DTRUE;
  87. TBOOLEAN        autoscale_lx    = DTRUE;
  88. TBOOLEAN        autoscale_ly    = DTRUE;
  89. TBOOLEAN        autoscale_lz    = DTRUE;
  90. TBOOLEAN        multiplot        = FALSE;
  91.  
  92. double            boxwidth    = -1.0; /* box width (automatic) */
  93. TBOOLEAN         clip_points    = FALSE;
  94. TBOOLEAN         clip_lines1    = TRUE;
  95. TBOOLEAN         clip_lines2    = FALSE;
  96. int            draw_border    = 31;
  97. TBOOLEAN        draw_surface    = TRUE;
  98. char            dummy_var[MAX_NUM_VAR][MAX_ID_LEN+1] = { "x", "y" };
  99. char            default_font[MAX_ID_LEN+1] = "\0"; /* Entry font added by DJL */
  100. char            xformat[MAX_ID_LEN+1] = DEF_FORMAT;
  101. char            yformat[MAX_ID_LEN+1] = DEF_FORMAT;
  102. char            zformat[MAX_ID_LEN+1] = DEF_FORMAT;
  103. char            x2format[MAX_ID_LEN+1] = DEF_FORMAT;
  104. char            y2format[MAX_ID_LEN+1] = DEF_FORMAT;
  105. /* do formats look like times - use FIRST_X_AXIS etc as index
  106.  * - never saved or shown ...
  107.  */
  108. #if AXIS_ARRAY_SIZE != 10
  109. #error error in initialiser for format_is_numeric
  110. #endif
  111.  
  112. int format_is_numeric[AXIS_ARRAY_SIZE] = { 1,1,1,1,1,1,1,1,1,1 };
  113.  
  114. enum PLOT_STYLE        data_style    = POINTSTYLE;
  115. enum PLOT_STYLE        func_style    = LINES;
  116. double        bar_size    = 1.0;
  117. int            grid        = GRID_OFF;
  118. int            grid_linetype   = -1;
  119. int            mgrid_linetype   = -1;
  120. double            polar_grid_angle= 0; /* nonzero means a polar grid */
  121. int            key        = -1;    /* default position */
  122. struct position key_user_pos;    /* user specified position for key */
  123. TBOOLEAN        key_reverse    = FALSE;  /* reverse text & sample ? */
  124. int            key_box        = -3; /* no linetype */
  125. TBOOLEAN        is_log_x    = FALSE;
  126. TBOOLEAN        is_log_y    = FALSE;
  127. TBOOLEAN        is_log_z    = FALSE;
  128. TBOOLEAN        is_log_x2    = FALSE;
  129. TBOOLEAN        is_log_y2    = FALSE;
  130. double            base_log_x    = 0.0;
  131. double            base_log_y    = 0.0;
  132. double            base_log_z    = 0.0;
  133. double            base_log_x2    = 0.0;
  134. double            base_log_y2    = 0.0;
  135. double            log_base_log_x    = 0.0;
  136. double            log_base_log_y    = 0.0;
  137. double            log_base_log_z    = 0.0;
  138. double            log_base_log_x2    = 0.0;
  139. double            log_base_log_y2    = 0.0;
  140. FILE*            outfile;
  141. char            outstr[MAX_ID_LEN+1] = "STDOUT";
  142. TBOOLEAN        parametric    = FALSE;
  143. double            pointsize    = 1.0;
  144. int            encoding;
  145. char            *encoding_names[] =
  146.                 {"default", "iso_8859_1", "cp437", "cp850", NULL};
  147. TBOOLEAN        polar        = FALSE;
  148. TBOOLEAN        hidden3d    = FALSE;
  149. TBOOLEAN        label_contours    = TRUE; /* different linestyles are used for contours when set */
  150. char contour_format[32] = "%8.3g"; /* format for contour key entries */
  151. int            angles_format    = ANGLES_RADIANS;
  152. double            ang2rad        = 1.0;  /* 1 or pi/180, tracking angles_format */
  153. int            mapping3d    = MAP3D_CARTESIAN;
  154. int            samples        = SAMPLES; /* samples is always equal to samples_1 */
  155. int            samples_1    = SAMPLES;
  156. int            samples_2    = SAMPLES;
  157. int            iso_samples_1    = ISO_SAMPLES;
  158. int            iso_samples_2    = ISO_SAMPLES;
  159. float            xsize        = 1.0;  /* scale factor for size */
  160. float            ysize        = 1.0;  /* scale factor for size */
  161. float            zsize        = 1.0;  /* scale factor for size */
  162. float            xoffset    = 0.0;  /* x origin */
  163. float            yoffset    = 0.0;  /* y origin */
  164. TBOOLEAN    square   = FALSE; /* dont try to set aspect ratio to 1 */
  165. float            surface_rot_z   = 30.0; /* Default 3d transform. */
  166. float            surface_rot_x   = 60.0;
  167. float            surface_scale   = 1.0;
  168. float            surface_zscale  = 1.0;
  169. struct termentry *term        = NULL;        /* unknown */
  170. char            term_options[MAX_LINE_LEN+1] = "";
  171. label_struct        title = { "", 0.0, 0.0, ""};
  172. label_struct        timelabel = { "", 0.0, 0.0, ""};
  173. label_struct        xlabel = {"", 0.0, 0.0, ""};
  174. label_struct        ylabel = {"", 0.0, 0.0, ""};
  175. label_struct        zlabel = {"", 0.0, 0.0, ""};
  176. label_struct        x2label = {"", 0.0, 0.0, ""};
  177. label_struct        y2label = {"", 0.0, 0.0, ""};
  178.  
  179. char            key_title[MAX_LINE_LEN+1] = "";
  180. double            rmin        = -0.0;
  181. double            rmax        =  10.0;
  182. double            tmin        = -5.0;
  183. double            tmax        =  5.0;
  184. double            umin        = -5.0;
  185. double            umax        = 5.0;
  186. double            vmin        = -5.0;
  187. double            vmax        = 5.0;
  188. double            xmin        = -10.0;
  189. double            xmax        = 10.0;
  190. double            ymin        = -10.0;
  191. double            ymax        = 10.0;
  192. double            zmin        = -10.0;
  193. double            zmax        = 10.0;
  194. double            x2min        = -10.0;
  195. double            x2max        = 10.0;
  196. double            y2min        = -10.0;
  197. double            y2max        = 10.0;
  198. double            loff        = 0.0;
  199. double            roff        = 0.0;
  200. double            toff        = 0.0;
  201. double            boff        = 0.0;
  202. int            draw_contour    = CONTOUR_NONE;
  203. int            contour_pts    = 5;
  204. int            contour_kind    = CONTOUR_KIND_LINEAR;
  205. int            contour_order    = 4;
  206. int            contour_levels    = 5;
  207. double            zero        = ZERO;    /* zero threshold, not 0! */
  208. int            levels_kind    = LEVELS_AUTO;
  209. double            levels_list[MAX_DISCRETE_LEVELS];  /* storage for z levels to draw contours at */
  210.  
  211. int            dgrid3d_row_fineness = 10;
  212. int            dgrid3d_col_fineness = 10;
  213. int            dgrid3d_norm_value = 1;
  214. TBOOLEAN        dgrid3d        = FALSE;
  215.  
  216. int         xzeroaxis    = -3;
  217. int         yzeroaxis    = -3;
  218. int         x2zeroaxis    = -3;
  219. int         y2zeroaxis    = -3;
  220.  
  221. /* perhaps make these into an array one day */
  222.  
  223. int         xtics        = TICS_ON_BORDER | TICS_MIRROR;
  224. int         ytics        = TICS_ON_BORDER | TICS_MIRROR;
  225. int         ztics        = TICS_ON_BORDER; /* no mirror by default for ztics */
  226. int         x2tics        = NO_TICS;
  227. int         y2tics        = NO_TICS;
  228.  
  229. int range_flags[AXIS_ARRAY_SIZE]; /* = {0,0,...} */
  230.  
  231. int                mxtics          = MINI_DEFAULT;
  232. int                mytics          = MINI_DEFAULT;
  233. int                mztics          = MINI_DEFAULT;
  234. int                mx2tics          = MINI_DEFAULT;
  235. int                my2tics          = MINI_DEFAULT;
  236.  
  237. double                  mxtfreq         = 10; /* # intervals between major */
  238. double                  mytfreq         = 10; /* tic marks */
  239. double                  mztfreq         = 10;
  240. double                  mx2tfreq         = 10;
  241. double                  my2tfreq         = 10;
  242.  
  243. double                  ticscale        = 1.0; /* scale factor for tic mark */
  244. double            miniticscale    = 0.5; /* and for minitics */
  245.  
  246. float             ticslevel    = 0.5;
  247.  
  248. struct ticdef        xticdef        = {TIC_COMPUTED};
  249. struct ticdef        yticdef        = {TIC_COMPUTED};
  250. struct ticdef        zticdef        = {TIC_COMPUTED};
  251. struct ticdef        x2ticdef        = {TIC_COMPUTED};
  252. struct ticdef        y2ticdef        = {TIC_COMPUTED};
  253.  
  254. TBOOLEAN        tic_in        = TRUE;
  255.  
  256. struct text_label     *first_label    = NULL;
  257. struct arrow_def     *first_arrow    = NULL;
  258.  
  259. int             lmargin        = -1; /* space between left edge and xleft in chars (-1: computed) */ 
  260. int             bmargin        = -1; /* space between bottom and ybot in chars (-1: computed) */ 
  261. int             rmargin        = -1; /* space between right egde and xright in chars (-1: computed) */ 
  262. int             tmargin        = -1; /* space between top egde and ytop in chars (-1: computed) */ 
  263.  
  264. /* string representing missing values in ascii datafiles */
  265. char *missing_val = NULL;
  266.  
  267. /* date&time language conversions */ 
  268. extern struct dtconv *dtc;
  269.  
  270. /*** other things we need *****/
  271.  
  272. #if defined(unix)
  273. extern FILE *popen();
  274. #endif
  275.  
  276. /* input data, parsing variables */
  277.  
  278. extern TBOOLEAN is_3d_plot;
  279.  
  280. /* term in graphics mode */
  281. extern TBOOLEAN term_graphics, term_suspended;
  282.  
  283. #ifdef _Windows
  284. extern FILE * open_printer();
  285. extern void close_printer();
  286. #endif
  287.  
  288. int key_hpos = TRIGHT;  /* place for curve-labels, corner or outside */
  289. int key_vpos = TTOP; /* place for curve-labels, corner or below */
  290. int key_just = JRIGHT;  /* alignment of key labels, left or right */
  291.  
  292. #ifndef TIMEFMT
  293. #define TIMEFMT "%d/%m/%y\n%H:%M"
  294. #endif
  295. /* format for date/time for reading time in datafile */
  296. char timefmt[25] = TIMEFMT;
  297.  
  298. /* array of datatypes (x in 0,y in 1,z in 2,..(rtuv)) */
  299. /* not sure how rtuv come into it ?
  300.  * oh well, make first six compatible with FIRST_X_AXIS, etc
  301.  */
  302. int datatype[DATATYPE_ARRAY_SIZE];
  303.  
  304. char cur_locale[MAX_ID_LEN+1] = "";
  305.  
  306. /* not set or shown directly, but controlled by 'set locale'
  307.  * defined in national.h
  308.  */
  309.  
  310. char full_month_names[12][32] = { FMON01, FMON02, FMON03, FMON04, FMON05, FMON06, FMON07, FMON08, FMON09, FMON10, FMON11, FMON12 };
  311. char abbrev_month_names[12][8] ={ AMON01, AMON02, AMON03, AMON04, AMON05, AMON06, AMON07, AMON08, AMON09, AMON10, AMON11, AMON12 };
  312.  
  313. char full_day_names[7][32] = { FDAY1, FDAY2, FDAY3, FDAY4, FDAY5, FDAY6, FDAY7 };
  314. char abbrev_day_names[7][8] = { ADAY1, ADAY2, ADAY3, ADAY4, ADAY5, ADAY6, ADAY7 };
  315.  
  316.  
  317.  
  318. /******** Local functions ********/
  319. static enum position_type get_position __P((struct position *pos, enum position_type type));
  320. static void get_position_type __P((enum position_type *type, int *axes));
  321. static void set_xyzlabel __P((label_struct *label));
  322. static void set_label __P((void));
  323. static void set_nolabel __P((void));
  324. static void set_arrow __P((void));
  325. static void set_noarrow __P((void));
  326. static void load_tics __P((int axis, struct ticdef *tdef));
  327. static void load_tic_user __P((int axis, struct ticdef *tdef));
  328. static void free_marklist __P((struct ticmark *list));
  329. static void load_tic_series __P((int axis, struct ticdef *tdef));
  330. static void load_offsets __P((double *a, double *b, double *c, double *d));
  331. static void delete_label __P((struct text_label *prev, struct text_label *this));
  332. static int assign_label_tag __P((void));
  333. static void delete_arrow __P((struct arrow_def *prev, struct arrow_def *this));
  334. static int assign_arrow_tag __P((void));
  335. static TBOOLEAN set_one __P((void));
  336. static TBOOLEAN set_two __P((void));
  337. static TBOOLEAN set_three __P((void));
  338. static int looks_like_numeric __P((char *));
  339. static void set_locale __P((char *));
  340.  
  341. /* following code segment appears over and over again */
  342. #define GET_NUM_OR_TIME(store,axis) \
  343. do{if ( datatype[axis] == TIME && isstring(c_token) ) { \
  344.     char ss[80]; struct tm tm; \
  345.     quote_str(ss,c_token, 80); ++c_token; \
  346.     if (gstrptime(ss,timefmt,&tm)) store = (double) gtimegm(&tm); else store=0;\
  347.    } else {\
  348.     struct value value; \
  349.     store = real(const_express(&value));\
  350.   }}while(0)
  351.  
  352. /******** The 'reset' command ********/
  353. void
  354. reset_command()
  355. {
  356.   extern struct curve_points *first_plot;
  357.   extern struct surface_points *first_3dplot;
  358.   register struct curve_points *f_p = first_plot;
  359.   register struct surface_points *f_3dp = first_3dplot;
  360.  
  361.   c_token++;
  362.   first_plot = NULL;
  363.   first_3dplot = NULL;
  364.   cp_free(f_p);
  365.   sp_free(f_3dp);
  366.   /* delete arrows */
  367.   while (first_arrow != NULL)
  368.     delete_arrow((struct arrow_def *)NULL,first_arrow);
  369.   /* delete labels */
  370.   while (first_label != NULL)
  371.     delete_label((struct text_label *)NULL,first_label);
  372.   strcpy(dummy_var[0],"x");
  373.   strcpy(dummy_var[1],"y");
  374.   strcpy(title.text,"");
  375.   strcpy(xlabel.text,"");
  376.   strcpy(ylabel.text,"");
  377.   strcpy(zlabel.text,"");
  378.   strcpy(x2label.text, "");
  379.   strcpy(y2label.text, "");
  380.   *title.font = 0;
  381.   *xlabel.font = 0;
  382.   *ylabel.font = 0;
  383.   *zlabel.font = 0;
  384.   *x2label.font = 0;
  385.   *y2label.font = 0;
  386.   strcpy(key_title,"");
  387.   strcpy(timefmt,TIMEFMT);
  388.   strcpy(xformat,DEF_FORMAT);
  389.   strcpy(yformat,DEF_FORMAT);
  390.   strcpy(zformat,DEF_FORMAT);
  391.   strcpy(x2format,DEF_FORMAT);
  392.   strcpy(y2format,DEF_FORMAT);
  393.   format_is_numeric[FIRST_X_AXIS]=format_is_numeric[SECOND_X_AXIS]=1;
  394.   format_is_numeric[FIRST_Y_AXIS]=format_is_numeric[SECOND_Y_AXIS]=1;
  395.   format_is_numeric[FIRST_Z_AXIS]=format_is_numeric[SECOND_Z_AXIS]=1;
  396.   autoscale_r     = DTRUE;
  397.   autoscale_t     = DTRUE;
  398.   autoscale_u     = DTRUE;
  399.   autoscale_v     = DTRUE;
  400.   autoscale_x     = DTRUE;
  401.   autoscale_y     = DTRUE;
  402.   autoscale_z     = DTRUE;
  403.   autoscale_lt     = DTRUE;
  404.   autoscale_lu     = DTRUE;
  405.   autoscale_lv     = DTRUE;
  406.   autoscale_lx     = DTRUE;
  407.   autoscale_ly     = DTRUE;
  408.   autoscale_lz     = DTRUE;
  409.   boxwidth     = -1.0;
  410.   clip_points     = FALSE;
  411.   clip_lines1     = TRUE;
  412.   clip_lines2     = FALSE;
  413.   draw_border     = 31;
  414.   draw_surface     = TRUE;
  415.   data_style     = POINTSTYLE;
  416.   func_style     = LINES;
  417.   bar_size        = 1.0;
  418.   grid         = GRID_OFF;
  419.   grid_linetype  = mgrid_linetype = -1;
  420.   polar_grid_angle=0;
  421.   key         = -1;
  422.   is_log_x     = FALSE;
  423.   is_log_y     = FALSE;
  424.   is_log_z     = FALSE;
  425.   is_log_x2     = FALSE;
  426.   is_log_y2     = FALSE;
  427.   base_log_x     = 0.0;
  428.   base_log_y     = 0.0;
  429.   base_log_z     = 0.0;
  430.   base_log_x2     = 0.0;
  431.   base_log_y2     = 0.0;
  432.   log_base_log_x = 0.0;
  433.   log_base_log_y = 0.0;
  434.   log_base_log_z = 0.0;
  435.   log_base_log_x2 = 0.0;
  436.   log_base_log_y2 = 0.0;
  437.   parametric     = FALSE;
  438.   polar         = FALSE;
  439.   hidden3d     = FALSE;
  440.   label_contours = TRUE;
  441.   strcpy(contour_format, "%8.3g");
  442.   angles_format     = ANGLES_RADIANS;
  443.   ang2rad     = 1.0; 
  444.   mapping3d     = MAP3D_CARTESIAN;
  445.   samples     = SAMPLES;
  446.   samples_1     = SAMPLES;
  447.   samples_2     = SAMPLES;
  448.   iso_samples_1     = ISO_SAMPLES;
  449.   iso_samples_2     = ISO_SAMPLES;
  450.   xsize         = 1.0;
  451.   ysize         = 1.0;
  452.   zsize         = 1.0;
  453.   xoffset    = 0.0;
  454.   yoffset    = 0.0;
  455.   square     = FALSE;
  456.   surface_rot_z     = 30.0;
  457.   surface_rot_x     = 60.0;
  458.   surface_scale     = 1.0;
  459.   surface_zscale = 1.0;
  460.   *timelabel.text = 0;
  461.   timelabel.xoffset     = 0;
  462.   timelabel.yoffset     = 0;
  463.   *timelabel.font = 0;
  464.   title.xoffset     = 0;
  465.   title.yoffset     = 0;
  466.   xlabel.xoffset = 0;
  467.   xlabel.yoffset = 0;
  468.   ylabel.xoffset = 0;
  469.   ylabel.yoffset = 0;
  470.   zlabel.xoffset = 0;
  471.   zlabel.yoffset = 0;
  472.   x2label.xoffset = 0;
  473.   x2label.yoffset = 0;
  474.   y2label.xoffset = 0;
  475.   y2label.yoffset = 0;
  476.   rmin         = -0.0;
  477.   rmax         =  10.0;
  478.   tmin         = -5.0;
  479.   tmax         =  5.0;
  480.   umin         = -5.0;
  481.   umax         = 5.0;
  482.   vmin         = -5.0;
  483.   vmax         = 5.0;
  484.   xmin         = -10.0;
  485.   xmax         = 10.0;
  486.   ymin         = -10.0;
  487.   ymax         = 10.0;
  488.   zmin         = -10.0;
  489.   zmax         = 10.0;
  490.   memset(range_flags, 0, sizeof(range_flags)); /* all = 0 */
  491.   
  492.   loff         = 0.0;
  493.   roff         = 0.0;
  494.   toff         = 0.0;
  495.   boff         = 0.0;
  496.   draw_contour     = CONTOUR_NONE;
  497.   contour_pts     = 5;
  498.   contour_kind     = CONTOUR_KIND_LINEAR;
  499.   contour_order     = 4;
  500.   contour_levels = 5;
  501.   zero         = ZERO;
  502.   levels_kind     = LEVELS_AUTO;
  503.   dgrid3d_row_fineness = 10;
  504.   dgrid3d_col_fineness = 10;
  505.   dgrid3d_norm_value   = 1;
  506.   dgrid3d     = FALSE;
  507.   xzeroaxis     =
  508.   yzeroaxis     =
  509.   x2zeroaxis     =
  510.   y2zeroaxis     = -3;
  511.   xtics         =
  512.   ytics         =
  513.   ztics         = TICS_ON_BORDER; /* no mirror by default */
  514.   x2tics     = NO_TICS;
  515.   y2tics     = NO_TICS;
  516.   mxtics     =
  517.   mytics     =
  518.   mztics  =
  519.   mx2tics =
  520.   my2tics = MINI_DEFAULT;
  521.   mxtfreq     = 10.0;
  522.   mytfreq     = 10.0;
  523.   mztfreq    = 10.0;
  524.   mx2tfreq   = 10.0;
  525.   my2tfreq   = 10.0;
  526.   ticscale     = 1.0;
  527.   miniticscale     = 0.5;
  528.   ticslevel     = 0.5;
  529.   xticdef.type     = TIC_COMPUTED;
  530.   yticdef.type     = TIC_COMPUTED;
  531.   zticdef.type     = TIC_COMPUTED;
  532.   x2ticdef.type     = TIC_COMPUTED;
  533.   y2ticdef.type     = TIC_COMPUTED;
  534.   tic_in     = TRUE;
  535.   lmargin     =
  536.   bmargin     =
  537.   rmargin     =
  538.   tmargin     = -1; /* autocomputed */
  539.   key_hpos     = TRIGHT;
  540.   key_vpos     = TTOP;
  541.   key_just     = JRIGHT;
  542.   key_reverse     = FALSE;
  543.   key_box     = -3;
  544.   datatype[FIRST_X_AXIS]     = FALSE;
  545.   datatype[FIRST_Y_AXIS]     = FALSE;
  546.   datatype[FIRST_Z_AXIS]     = FALSE;
  547.   datatype[SECOND_X_AXIS]     = FALSE;
  548.   datatype[SECOND_Y_AXIS]     = FALSE;
  549.   datatype[SECOND_Z_AXIS]     = FALSE;
  550.   datatype[R_AXIS] = FALSE;
  551.   datatype[T_AXIS] = FALSE;
  552.   datatype[U_AXIS] = FALSE;
  553.   datatype[V_AXIS] = FALSE;
  554.  
  555.   pointsize = 1.0;
  556.   if (term_init && term->set_pointsize)
  557.       (*term->set_pointsize)(1.0);
  558.   encoding = ENCODING_DEFAULT;
  559.  
  560.   set_locale(""); /* default */
  561. }
  562.  
  563. /******** The 'set' command ********/
  564. void
  565. set_command()
  566. {
  567. static char GPFAR setmess[] ="\
  568. valid set options:  [] = choose one, {} means optional\n\
  569. \t'angles' '{no}arrow', {no}autoscale', 'bars', '{no}border',\n\
  570. \t'boxwidth', '{no}clabel', '{no}clip', 'cntrparam', '{no}contour',\n\
  571. \t'data style', '{no}dgrid3d', 'dummy', 'format',\n\
  572. \t'function style', '{no}grid', '{no}hidden3d', 'isosamples', '{no}key',\n\
  573. \t'keytitle','{no}label', 'locale', '{no}logscale', '[blrt]margin',\n\
  574. \t'mapping', 'missing', 'offsets', 'origin', 'output', '{no}parametric',\n\
  575. \t'pointsize', '{no}polar', '[rtuv]range', 'samples', 'size',\n\
  576. \t'{no}surface', 'terminal', 'tics', 'ticscale', 'ticslevel',\n\
  577. \t'{no}time', 'timefmt', 'title', 'view', '[xyz]{2}data', '[xyz]{2}label',\n\
  578. \t'[xyz]{2}range', '{no}{m}[xyz]{2}tics','{no}[xyz]{2}[md]tics',\n\
  579. \t'{no}[xyz]{2}zeroaxis', 'zero', '{no}zeroaxis'";
  580.  
  581.  
  582.     c_token++;
  583.  
  584.     if (!set_one() && !set_two() && !set_three())
  585.     int_error(setmess, c_token);
  586. }
  587.  
  588. /* return TRUE if a command match, FALSE if not */
  589. static TBOOLEAN
  590. set_one()
  591. {
  592.     if (almost_equals(c_token,"ar$row")) {
  593.         c_token++;
  594.         set_arrow();
  595.     }
  596.     else if (almost_equals(c_token,"noar$row")) {
  597.         c_token++;
  598.         set_noarrow();
  599.     }
  600.  
  601. /* save on replication with a macro */
  602. #define PROCESS_AUTO_LETTER(AUTO, STRING,MIN,MAX) \
  603. else if (equals(c_token, STRING))       { AUTO = DTRUE; ++c_token; } \
  604. else if (almost_equals(c_token, MIN)) { AUTO |= 1;    ++c_token; } \
  605. else if (almost_equals(c_token, MAX)) { AUTO |= 2;    ++c_token; }
  606.  
  607.      else if (almost_equals(c_token,"au$toscale")) {
  608.         c_token++;
  609.         if (END_OF_COMMAND) {
  610.            autoscale_r=autoscale_t = autoscale_x = autoscale_y = autoscale_z = DTRUE;
  611.         } else if (equals(c_token, "xy") || equals(c_token, "yx")) {
  612.            autoscale_x = autoscale_y = DTRUE;
  613.            c_token++;
  614.         }
  615.         PROCESS_AUTO_LETTER(autoscale_r, "r", "rmi$n", "rma$x")
  616.         PROCESS_AUTO_LETTER(autoscale_t, "t", "tmi$n", "tma$x")
  617.         PROCESS_AUTO_LETTER(autoscale_u, "u", "umi$n", "uma$x")
  618.         PROCESS_AUTO_LETTER(autoscale_v, "v", "vmi$n", "vma$x")
  619.         PROCESS_AUTO_LETTER(autoscale_x, "x", "xmi$n", "xma$x")
  620.         PROCESS_AUTO_LETTER(autoscale_y, "y", "ymi$n", "yma$x")
  621.         PROCESS_AUTO_LETTER(autoscale_z, "z", "zmi$n", "zma$x")
  622.         PROCESS_AUTO_LETTER(autoscale_x2, "x2", "x2mi$n", "x2ma$x")
  623.         PROCESS_AUTO_LETTER(autoscale_y2, "y2", "y2mi$n", "y2ma$x")
  624.         else
  625.         int_error("Invalid range", c_token);
  626.     } 
  627.     else if (almost_equals(c_token,"noau$toscale")) {
  628.         c_token++;
  629.         if (END_OF_COMMAND) {
  630.            autoscale_r=autoscale_t = autoscale_x = autoscale_y = autoscale_z = FALSE;
  631.         } else if (equals(c_token, "xy") || equals(c_token, "tyx")) {
  632.            autoscale_x = autoscale_y = FALSE;
  633.            c_token++;
  634.         } else if (equals(c_token, "r")) {
  635.            autoscale_r = FALSE;
  636.            c_token++;
  637.         } else if (equals(c_token, "t")) {
  638.            autoscale_t = FALSE;
  639.            c_token++;
  640.         } else if (equals(c_token, "u")) {
  641.            autoscale_u = FALSE;
  642.            c_token++;
  643.         } else if (equals(c_token, "v")) {
  644.            autoscale_v = FALSE;
  645.            c_token++;
  646.         } else if (equals(c_token, "x")) {
  647.            autoscale_x = FALSE;
  648.            c_token++;
  649.         } else if (equals(c_token, "y")) {
  650.            autoscale_y = FALSE;
  651.            c_token++;
  652.         } else if (equals(c_token, "z")) {
  653.            autoscale_z = FALSE;
  654.            c_token++;
  655.         }
  656.     } 
  657.     else if (almost_equals(c_token,"nobor$der")) {
  658.         draw_border = 0;
  659.         c_token++;
  660.     }
  661.     else if (almost_equals(c_token,"box$width")) {
  662.         struct value a;
  663.         c_token++;
  664.         if (END_OF_COMMAND)
  665.             boxwidth = -1.0;
  666.         else
  667. /*              if((boxwidth = real(const_express(&a))) != -2.0)*/
  668. /*                      boxwidth = magnitude(const_express(&a));*/
  669.                 boxwidth = real(const_express(&a));
  670.     }
  671.     else if (almost_equals(c_token,"c$lip")) {
  672.         c_token++;
  673.         if (END_OF_COMMAND)
  674.          /* assuming same as points */
  675.          clip_points = TRUE;
  676.         else if (almost_equals(c_token, "p$oints"))
  677.          clip_points = TRUE;
  678.         else if (almost_equals(c_token, "o$ne"))
  679.          clip_lines1 = TRUE;
  680.         else if (almost_equals(c_token, "t$wo"))
  681.          clip_lines2 = TRUE;
  682.         else
  683.          int_error("expecting 'points', 'one', or 'two'", c_token);
  684.         c_token++;
  685.     }
  686.     else if (almost_equals(c_token,"noc$lip")) {
  687.         c_token++;
  688.         if (END_OF_COMMAND) {
  689.            /* same as all three */
  690.            clip_points = FALSE;
  691.            clip_lines1 = FALSE;
  692.            clip_lines2 = FALSE;
  693.         } else if (almost_equals(c_token, "p$oints"))
  694.          clip_points = FALSE;
  695.         else if (almost_equals(c_token, "o$ne"))
  696.          clip_lines1 = FALSE;
  697.         else if (almost_equals(c_token, "t$wo"))
  698.          clip_lines2 = FALSE;
  699.         else
  700.          int_error("expecting 'points', 'one', or 'two'", c_token);
  701.         c_token++;
  702.     }
  703.     else if (almost_equals(c_token,"hi$dden3d")) {
  704. #ifdef LITE
  705.         printf(" Hidden Line Removal Not Supported in LITE version\n");
  706. #else
  707.         hidden3d = TRUE;
  708. #endif /* LITE */
  709.         c_token++;
  710.     }
  711.     else if (almost_equals(c_token,"nohi$dden3d")) {
  712. #ifdef LITE
  713.         printf(" Hidden Line Removal Not Supported in LITE version\n");
  714. #else
  715.         hidden3d = FALSE;
  716. #endif /* LITE */
  717.         c_token++;
  718.     }
  719.      else if (almost_equals(c_token,"cla$bel")) {
  720.          label_contours = TRUE;
  721.          c_token++;
  722.          if (isstring(c_token))
  723.              quote_str(contour_format, c_token++, 30);
  724.      }
  725.      else if (almost_equals(c_token,"nocla$bel")) {
  726.          label_contours = FALSE;
  727.          c_token++;
  728.       }
  729.     else if (almost_equals(c_token,"ma$pping3d")) {
  730.         c_token++;
  731.         if (END_OF_COMMAND)
  732.          /* assuming same as points */
  733.          mapping3d = MAP3D_CARTESIAN;
  734.         else if (almost_equals(c_token, "ca$rtesian"))
  735.          mapping3d = MAP3D_CARTESIAN;
  736.         else if (almost_equals(c_token, "s$pherical"))
  737.          mapping3d = MAP3D_SPHERICAL;
  738.         else if (almost_equals(c_token, "cy$lindrical"))
  739.          mapping3d = MAP3D_CYLINDRICAL;
  740.         else
  741.          int_error("expecting 'cartesian', 'spherical', or 'cylindrical'", c_token);
  742.         c_token++;
  743.     }
  744.     else if (almost_equals(c_token,"co$ntour")) {
  745.       c_token++;
  746.       if (END_OF_COMMAND)
  747.          /* assuming same as points */
  748.          draw_contour = CONTOUR_BASE;
  749.       else {
  750.         if (almost_equals(c_token, "ba$se"))
  751.          draw_contour = CONTOUR_BASE;
  752.         else if (almost_equals(c_token, "s$urface"))
  753.          draw_contour = CONTOUR_SRF;
  754.         else if (almost_equals(c_token, "bo$th"))
  755.          draw_contour = CONTOUR_BOTH;
  756.         else
  757.          int_error("expecting 'base', 'surface', or 'both'", c_token);
  758.         c_token++;
  759.       }
  760.     }
  761.     else if (almost_equals(c_token,"noco$ntour")) {
  762.         c_token++;
  763.         draw_contour = CONTOUR_NONE;
  764.     }
  765.     else if (almost_equals(c_token,"cntrp$aram")) {
  766.         struct value a;
  767.  
  768.         c_token++;
  769.         if (END_OF_COMMAND) {
  770.          /* assuming same as defaults */
  771.          contour_pts = 5;
  772.          contour_kind = CONTOUR_KIND_LINEAR;
  773.          contour_order = 4;
  774.          contour_levels = 5;
  775.           levels_kind = LEVELS_AUTO;
  776.         }
  777.         else if (almost_equals(c_token, "p$oints")) {
  778.          c_token++;
  779.          contour_pts = (int) real(const_express(&a));
  780.         }
  781.         else if (almost_equals(c_token, "li$near")) {
  782.          c_token++;
  783.          contour_kind = CONTOUR_KIND_LINEAR;
  784.         }
  785.         else if (almost_equals(c_token, "c$ubicspline")) {
  786.          c_token++;
  787.          contour_kind = CONTOUR_KIND_CUBIC_SPL;
  788.         }
  789.         else if (almost_equals(c_token, "b$spline")) {
  790.          c_token++;
  791.          contour_kind = CONTOUR_KIND_BSPLINE;
  792.         }
  793.  
  794.            else if (almost_equals(c_token, "le$vels")) {
  795.                int i=0;  /* local counter */
  796.                c_token++;
  797.             /*  RKC: I have modified the next two:
  798.              *   to use commas to separate list elements as in xtics
  799.               *   so that incremental lists start,incr[,end]as in "
  800.               */
  801.                if (almost_equals(c_token, "di$screte")) {
  802.                   levels_kind = LEVELS_DISCRETE;
  803.                   c_token++;
  804.                 if(END_OF_COMMAND)
  805.                  int_error("expecting discrete level", c_token);
  806.                 else
  807.                   levels_list[i++] = real(const_express(&a));
  808.                 while(!END_OF_COMMAND){
  809.                   if (!equals(c_token, ","))
  810.                     int_error("expecting comma to separate discrete levels", c_token);
  811.                   c_token++;
  812.                   levels_list[i++] =  real(const_express(&a));
  813.                 }
  814.                   contour_levels = i;
  815.                }
  816.                else if (almost_equals(c_token, "in$cremental")) {
  817.                   levels_kind = LEVELS_INCREMENTAL;
  818.                   c_token++;
  819.                 levels_list[i++] =  real(const_express(&a));
  820.                 if (!equals(c_token, ","))
  821.                   int_error("expecting comma to separate start,incr levels", c_token);
  822.                 c_token++;
  823.                 if((levels_list[i++] = real(const_express(&a)))==0)
  824.                   int_error("increment cannot be 0", c_token);
  825.                  if(!END_OF_COMMAND){
  826.                   if (!equals(c_token, ","))
  827.                     int_error("expecting comma to separate incr,stop levels", c_token);
  828.                   c_token++;
  829.                  contour_levels = (real(const_express(&a))-levels_list[0])/levels_list[1];
  830.                   }
  831.                }
  832.                else if (almost_equals(c_token, "au$to")) {
  833.                    levels_kind = LEVELS_AUTO;
  834.                  c_token++;
  835.                  if(!END_OF_COMMAND)
  836.                      contour_levels = (int) real(const_express(&a));
  837.              }
  838.              else {
  839.               if(levels_kind == LEVELS_DISCRETE)
  840.                 int_error("Levels type is discrete, ignoring new number of contour levels", c_token);
  841.                 contour_levels = (int) real(const_express(&a));
  842.             }
  843.          }
  844.         else if (almost_equals(c_token, "o$rder")) {
  845.          int order;
  846.          c_token++;
  847.          order = (int) real(const_express(&a));
  848.          if ( order < 2 || order > 10 )
  849.              int_error("bspline order must be in [2..10] range.", c_token);
  850.          contour_order = order;
  851.         }
  852.         else
  853.          int_error("expecting 'linear', 'cubicspline', 'bspline', 'points', 'levels' or 'order'", c_token);
  854.         c_token++;
  855.     }
  856.     else if (almost_equals(c_token,"da$ta")) {
  857.         c_token++;
  858.         if (!almost_equals(c_token,"s$tyle"))
  859.             int_error("expecting keyword 'style'",c_token);
  860.         data_style = get_style();
  861.     }
  862.     else if (almost_equals(c_token,"dg$rid3d")) {
  863.         int i;
  864.         TBOOLEAN was_comma = TRUE;
  865.         int local_vals[3];
  866.         struct value a;
  867.  
  868.         local_vals[0] = dgrid3d_row_fineness;
  869.         local_vals[1] = dgrid3d_col_fineness;
  870.         local_vals[2] = dgrid3d_norm_value;
  871.         c_token++;
  872.         for (i = 0; i < 3 && !(END_OF_COMMAND);) {
  873.             if (equals(c_token,",")) {
  874.                 if (was_comma) i++;
  875.                 was_comma = TRUE;
  876.                 c_token++;
  877.             }
  878.             else {
  879.                 if (!was_comma)
  880.                     int_error("',' expected",c_token);
  881.                 local_vals[i] = real(const_express(&a));
  882.                 i++;
  883.                 was_comma = FALSE;
  884.             }
  885.         }
  886.  
  887.  
  888.         if (local_vals[0] < 2 || local_vals[0] > 1000)
  889.             int_error("Row size must be in [2:1000] range; size unchanged",
  890.                   c_token);
  891.         if (local_vals[1] < 2 || local_vals[1] > 1000)
  892.             int_error("Col size must be in [2:1000] range; size unchanged",
  893.                   c_token);
  894.         if (local_vals[2] < 1 || local_vals[2] > 100)
  895.             int_error("Norm must be in [1:100] range; norm unchanged", c_token);
  896.  
  897.         dgrid3d_row_fineness = local_vals[0];
  898.         dgrid3d_col_fineness = local_vals[1];
  899.         dgrid3d_norm_value = local_vals[2];
  900.         dgrid3d = TRUE;
  901.     }
  902.     else if (almost_equals(c_token,"nodg$rid3d")) {
  903.         c_token++;
  904.         dgrid3d = FALSE;
  905.     }
  906.     else if (almost_equals(c_token,"mis$sing")) {
  907.         c_token++;
  908.         if (END_OF_COMMAND) {
  909.             if (missing_val)
  910.                 free(missing_val);
  911.             missing_val = NULL;
  912.         } else {
  913.             if (!isstring(c_token))
  914.                 int_error("Expected missing-value string", c_token);
  915.             m_quote_capture(&missing_val, c_token, c_token);
  916.             c_token++;
  917.         }
  918.     }
  919.     else if (almost_equals(c_token,"nomis$sing")) {
  920.         ++c_token;
  921.         if (missing_val)
  922.             free(missing_val);
  923.         missing_val = NULL;
  924.     }
  925.     else if (almost_equals(c_token,"du$mmy")) {
  926.         c_token++;
  927.         if (END_OF_COMMAND)
  928.             int_error("expecting dummy variable name", c_token);
  929.         else {
  930.             if (!equals(c_token,","))
  931.                 copy_str(dummy_var[0],c_token++, MAX_ID_LEN);
  932.             if (!END_OF_COMMAND && equals(c_token,",")) {
  933.                 c_token++;
  934.                 if (END_OF_COMMAND)
  935.                     int_error("expecting second dummy variable name", c_token);
  936.                 copy_str(dummy_var[1],c_token++, MAX_ID_LEN);
  937.                 }
  938.         }
  939.     }
  940.     else if (almost_equals(c_token,"fo$rmat")) {
  941.         TBOOLEAN setx=FALSE, sety=FALSE, setz=FALSE;
  942.         TBOOLEAN setx2=FALSE, sety2=FALSE;
  943.         c_token++;
  944.         if (equals(c_token,"x")) {
  945.             setx = TRUE;
  946.             c_token++;
  947.         }
  948.         else if (equals(c_token,"y")) {
  949.             sety = TRUE;
  950.             c_token++;
  951.         }
  952.         else if (equals(c_token,"x2")) {
  953.             setx2 = TRUE;
  954.             c_token++;
  955.         }
  956.         else if (equals(c_token,"y2")) {
  957.             sety2 = TRUE;
  958.             c_token++;
  959.         }
  960.         else if (equals(c_token,"z")) {
  961.             setz = TRUE;
  962.             c_token++;
  963.         }
  964.         else if (equals(c_token,"xy") || equals(c_token,"yx")) {
  965.             setx = sety = TRUE;
  966.             c_token++;
  967.         }
  968.         else if (isstring(c_token) || END_OF_COMMAND) {
  969.             /* Assume he wants all */
  970.             setx = sety = setz = setx2 = sety2 = TRUE;
  971.         }
  972.         if (END_OF_COMMAND) {
  973.             if (setx) {
  974.                 (void) strcpy(xformat,DEF_FORMAT);
  975.                 format_is_numeric[FIRST_X_AXIS]=1;
  976.             }
  977.             if (sety) {
  978.                 (void) strcpy(yformat,DEF_FORMAT);
  979.                 format_is_numeric[FIRST_Y_AXIS]=1;
  980.             }
  981.             if (setz) {
  982.                 (void) strcpy(zformat,DEF_FORMAT);
  983.                 format_is_numeric[FIRST_Z_AXIS]=1;
  984.             }
  985.             if (setx2) {
  986.                 (void) strcpy(x2format,DEF_FORMAT);
  987.                 format_is_numeric[SECOND_X_AXIS]=1;
  988.             }
  989.             if (sety2) {
  990.                 (void) strcpy(y2format,DEF_FORMAT);
  991.                 format_is_numeric[SECOND_Y_AXIS]=1;
  992.             }
  993.         }
  994.         else {
  995.             if (!isstring(c_token))
  996.               int_error("expecting format string",c_token);
  997.             else {
  998.                 if (setx) {
  999.                  quote_str(xformat,c_token, MAX_ID_LEN);
  1000.                  format_is_numeric[FIRST_X_AXIS]=looks_like_numeric(xformat);
  1001.                 }
  1002.                 if (sety) {
  1003.                  quote_str(yformat,c_token, MAX_ID_LEN);
  1004.                  format_is_numeric[FIRST_X_AXIS]=looks_like_numeric(yformat);
  1005.                 }
  1006.                 if (setz) {
  1007.                  quote_str(zformat,c_token, MAX_ID_LEN);
  1008.                  format_is_numeric[FIRST_X_AXIS]=looks_like_numeric(zformat);
  1009.                 }
  1010.                 if (setx2) {
  1011.                  quote_str(x2format,c_token, MAX_ID_LEN);
  1012.                  format_is_numeric[SECOND_X_AXIS]=looks_like_numeric(x2format);
  1013.                 }
  1014.                 if (sety2) {
  1015.                  quote_str(y2format,c_token, MAX_ID_LEN);
  1016.                  format_is_numeric[SECOND_Y_AXIS]=looks_like_numeric(y2format);
  1017.                 }
  1018.                 c_token++;
  1019.             }
  1020.         }
  1021.     }
  1022.     else if (almost_equals(c_token,"fu$nction")) {
  1023.         c_token++;
  1024.         if (!almost_equals(c_token,"s$tyle"))
  1025.             int_error("expecting keyword 'style'",c_token);
  1026.         func_style = get_style();
  1027.     }
  1028.     else if (almost_equals(c_token,"la$bel")) {
  1029.         c_token++;
  1030.         set_label();
  1031.     }
  1032.     else if (almost_equals(c_token,"nola$bel")) {
  1033.         c_token++;
  1034.         set_nolabel();
  1035.     }
  1036.     else if (almost_equals(c_token,"lo$gscale")) {
  1037.         c_token++;
  1038.         if (END_OF_COMMAND) {
  1039.         is_log_x = is_log_y = is_log_z = is_log_x2 = is_log_y2 = TRUE;
  1040.         base_log_x = base_log_y = base_log_z = base_log_x2 = base_log_y2 = 10.0;
  1041.         log_base_log_x = log_base_log_y = log_base_log_z = log_base_log_x2 = log_base_log_y2 = log(10.0);
  1042.         } else {
  1043.         TBOOLEAN change_x = FALSE;
  1044.         TBOOLEAN change_y = FALSE;
  1045.         TBOOLEAN change_z = FALSE;
  1046.         TBOOLEAN change_x2 = FALSE;
  1047.         TBOOLEAN change_y2 = FALSE;
  1048.         double newbase=10, log_newbase;
  1049.  
  1050.         if (equals(c_token, "x2"))
  1051.             change_x2 = TRUE;
  1052.         else if (equals(c_token, "y2"))
  1053.             change_y2 = TRUE;
  1054.         else { /* must not see x when x2, etc */
  1055.             if (chr_in_str(c_token, 'x'))
  1056.             change_x = TRUE;
  1057.             if (chr_in_str(c_token, 'y'))
  1058.             change_y = TRUE;
  1059.             if (chr_in_str(c_token, 'z'))
  1060.             change_z = TRUE;
  1061.         }
  1062.         c_token++;
  1063.                 if (!END_OF_COMMAND) {
  1064.             struct value a;
  1065.             newbase = magnitude(const_express(&a));
  1066.             if (newbase < 1.1)
  1067.                 int_error("log base must be >= 1.1; logscale unchanged",
  1068.                 c_token);
  1069.         }
  1070.  
  1071.         log_newbase = log(newbase);
  1072.  
  1073.             if (change_x) {
  1074.                 is_log_x = TRUE;
  1075.                 base_log_x = newbase;
  1076.                 log_base_log_x = log_newbase;
  1077.             }
  1078.             if (change_y) {
  1079.                 is_log_y = TRUE;
  1080.                 base_log_y = newbase;
  1081.                 log_base_log_y = log_newbase;
  1082.             }
  1083.             if (change_z) {
  1084.                 is_log_z = TRUE;
  1085.                 base_log_z = newbase;
  1086.                 log_base_log_z = log_newbase;
  1087.             }
  1088.             if (change_x2) {
  1089.                 is_log_x2 = TRUE;
  1090.                 base_log_x2 = newbase;
  1091.                 log_base_log_x2 = log_newbase;
  1092.             }
  1093.             if (change_y2) {
  1094.                 is_log_y2 = TRUE;
  1095.                 base_log_y2 = newbase;
  1096.                 log_base_log_y2 = log_newbase;
  1097.             }
  1098.         }
  1099.     }
  1100.     else if (almost_equals(c_token,"nolo$gscale")) {
  1101.         c_token++;
  1102.         if (END_OF_COMMAND) {
  1103.         is_log_x = is_log_y = is_log_z = is_log_x2 = is_log_y2 = FALSE;
  1104.         } else if (equals(c_token, "x2")) {
  1105.         is_log_x2=FALSE; ++c_token;
  1106.         } else if (equals(c_token, "y2")) {
  1107.         is_log_y2=FALSE; ++c_token;
  1108.         } else {
  1109.         if (chr_in_str(c_token, 'x')) {
  1110.             is_log_x = FALSE;
  1111.             base_log_x = 0.0;
  1112.             log_base_log_x = 0.0;
  1113.                 }
  1114.         if (chr_in_str(c_token, 'y')) {
  1115.             is_log_y = FALSE;
  1116.             base_log_y = 0.0;
  1117.             log_base_log_y = 0.0;
  1118.                 }
  1119.         if (chr_in_str(c_token, 'z')) {
  1120.             is_log_z = FALSE;
  1121.             base_log_z = 0.0;
  1122.             log_base_log_z = 0.0;
  1123.                 }
  1124.         c_token++;
  1125.         }
  1126.     } 
  1127.     else if (almost_equals(c_token,"of$fsets")) {
  1128.         c_token++;
  1129.         if (END_OF_COMMAND) {
  1130.             loff = roff = toff = boff = 0.0;  /* Reset offsets */
  1131.         }
  1132.         else {
  1133.             load_offsets (&loff,&roff,&toff,&boff);
  1134.         }
  1135.     }
  1136.     else if (almost_equals(c_token, "noof$fsets")) {
  1137.         loff = roff = toff = boff = 0.0;
  1138.         ++c_token;
  1139.     }
  1140.         else if(almost_equals(c_token,"b$ars")){
  1141.            c_token++;
  1142.            if(END_OF_COMMAND){
  1143.                    bar_size=1.0;
  1144.            } else if(almost_equals(c_token,"s$mall")){
  1145.               bar_size=0.0;
  1146.               ++c_token;
  1147.            } else if(almost_equals(c_token,"l$arge")){
  1148.               bar_size=1.0;
  1149.               ++c_token;
  1150.            } else {
  1151.                    struct value a;
  1152.                    bar_size=real(const_express(&a));
  1153.            }
  1154.         } else if (almost_equals(c_token, "nob$ars")){
  1155.                 ++c_token;
  1156.                 bar_size=0.0;
  1157.         } else if (almost_equals(c_token, "enco$ding")){
  1158.         c_token++;
  1159.         if(END_OF_COMMAND) {
  1160.         encoding = ENCODING_DEFAULT;
  1161.         }
  1162.         else if (almost_equals(c_token,"def$ault")) {
  1163.         c_token++;
  1164.         encoding = ENCODING_DEFAULT;
  1165.         }
  1166.             else if (almost_equals(c_token,"iso$_8859_1")) {
  1167.         c_token++;
  1168.         encoding = ENCODING_ISO_8859_1;
  1169.         }
  1170.         else if (almost_equals(c_token,"cp4$37")) {
  1171.         c_token++;
  1172.         encoding = ENCODING_CP_437;
  1173.         }
  1174.         else if (almost_equals(c_token,"cp8$50")) {
  1175.         c_token++;
  1176.         encoding = ENCODING_CP_850;
  1177.         }
  1178.         else {
  1179.            int_error("expecting one of 'default', 'iso_8859_1', 'cp437' or 'cp850'",
  1180.             c_token);
  1181.         }
  1182.         } else return(FALSE);  /* no command match */
  1183.     return(TRUE);
  1184. }
  1185.  
  1186.  
  1187. /* return TRUE if a command match, FALSE if not */
  1188. static TBOOLEAN
  1189. set_two()
  1190. {
  1191.      char testfile[MAX_LINE_LEN+1];
  1192. #if defined(unix) || defined(PIPES)
  1193.      static TBOOLEAN pipe_open = FALSE;
  1194. #endif /* unix || PIPES */
  1195.  
  1196.     if (almost_equals(c_token,"o$utput")) {
  1197.      if (multiplot) {
  1198.          fprintf(stderr,"In multiplotmode you can't change the output\n");
  1199.        } else {
  1200.         register FILE *f;
  1201.  
  1202.         c_token++;
  1203.         if (term && term_init) {
  1204.             (*term->reset)();
  1205.             term_init=FALSE;
  1206.         }
  1207.         if (END_OF_COMMAND) {    /* no file specified */
  1208.              UP_redirect (4);
  1209.             if (outfile != stdout) { /* Never close stdout */
  1210. #if defined(unix) || defined(PIPES)
  1211.                 if ( pipe_open ) {
  1212.                     (void) pclose(outfile);
  1213.                     pipe_open = FALSE;
  1214.                 } else
  1215. #endif /* unix || PIPES */
  1216. #ifdef _Windows
  1217.                   if ( !stricmp(outstr,"'PRN'") )
  1218.                     close_printer();
  1219.                   else
  1220. #endif
  1221.                     (void) fclose(outfile);
  1222.             }
  1223.             outfile = stdout; /* Don't dup... */
  1224.             term_init = FALSE;
  1225.             (void) strcpy(outstr,"STDOUT");
  1226.         } else if (!isstring(c_token))
  1227.             int_error("expecting filename",c_token);
  1228.         else {
  1229.             quote_str(testfile,c_token, MAX_LINE_LEN);
  1230. #if defined(unix) || defined(PIPES)
  1231.             if ( *testfile == '|' ) {
  1232.               if ((f = popen(testfile+1,"w")) == (FILE *)NULL)
  1233.                 os_error("cannot create pipe; output not changed",c_token);
  1234.               else
  1235.                 pipe_open = TRUE;
  1236.             } else
  1237. #endif /* unix || PIPES */
  1238. #ifdef _Windows
  1239.             if ( !stricmp(outstr,"'PRN'") ) {
  1240.                 /* we can't call open_printer() while printer is open, so */
  1241.                 close_printer();    /* close printer immediately if open */
  1242.                 outfile = stdout;    /* and reset output to stdout */
  1243.                 term_init = FALSE;
  1244.                 (void) strcpy(outstr,"STDOUT");
  1245.             }
  1246.             if ( !stricmp(testfile,"PRN") ) {
  1247.               if ((f = open_printer()) == (FILE *)NULL)
  1248.                 os_error("cannot open printer temporary file; output may have changed",c_token);
  1249.             } else
  1250. #endif
  1251.               if ((f = fopen(testfile,"w")) == (FILE *)NULL)
  1252.                 os_error("cannot open file; output not changed",c_token);
  1253.             if (outfile != stdout) /* Never close stdout */
  1254. #if defined(unix) || defined(PIPES)
  1255.                 if( pipe_open ) {
  1256.                 (void) pclose(outfile);
  1257.                 pipe_open=FALSE;
  1258.                 } else
  1259. #endif /* unix || PIPES */
  1260.                 (void) fclose(outfile);
  1261.             outfile = f;
  1262.             term_init = FALSE;
  1263.             outstr[0] = '\'';
  1264.             (void) strcat(strcpy(outstr+1,testfile),"'");
  1265.              UP_redirect (1);
  1266.             c_token++;
  1267.         }
  1268.       }
  1269.         /* c_token++; */
  1270.     }
  1271.      else if (almost_equals(c_token,"origin")) {
  1272.          struct value s;
  1273.          c_token++;
  1274.          if (END_OF_COMMAND) {
  1275.              xoffset = 0.0;
  1276.              yoffset = 0.0;
  1277.          } 
  1278.          else {
  1279.                  xoffset=real(const_express(&s));
  1280.                  if (!equals(c_token,","))
  1281.                      int_error("',' expected",c_token);
  1282.                  c_token++;
  1283.                  yoffset=real(const_express(&s));
  1284.          } 
  1285.      } 
  1286.     else if (almost_equals(c_token,"tit$le")) {
  1287.         set_xyzlabel(&title);
  1288.     }
  1289.     else if (almost_equals(c_token,"xl$abel")) {
  1290.         set_xyzlabel(&xlabel);
  1291.     }
  1292.     else if (almost_equals(c_token,"yl$abel")) {
  1293.         set_xyzlabel(&ylabel);
  1294.     }
  1295.     else if (almost_equals(c_token,"zl$abel")) {
  1296.         set_xyzlabel(&zlabel);
  1297.     }
  1298.     else if (almost_equals(c_token,"x2l$abel")) {
  1299.         set_xyzlabel(&x2label);
  1300.     }
  1301.     else if (almost_equals(c_token,"y2l$abel")) {
  1302.         set_xyzlabel(&y2label);
  1303.     }
  1304.     else if (almost_equals(c_token,"keyt$itle")) {
  1305.         c_token++;
  1306.         if (END_OF_COMMAND) {    /* set to default */
  1307.             key_title[0] = '\0';
  1308.         } else {
  1309.             if (isstring(c_token)) {
  1310.                 /* We have string specified - grab it. */
  1311.                 quote_str(key_title,c_token, MAX_LINE_LEN);
  1312.                 c_token++;
  1313.             }
  1314.             /* c_token++; */
  1315.         }
  1316.     }
  1317.     else if (almost_equals(c_token, "nokeyt$itle")) {
  1318.         ++c_token;
  1319.         *key_title=0;
  1320.     }
  1321.     else if (almost_equals(c_token,"timef$mt")) {
  1322.         c_token++;
  1323.         if (END_OF_COMMAND) {    /* set to default */
  1324.             strcpy(timefmt,TIMEFMT);
  1325.         } else {
  1326.             if (isstring(c_token)) {
  1327.                 /* We have string specified - grab it. */
  1328.                 quote_str(timefmt,c_token, 25);
  1329.             }
  1330.             c_token++;
  1331.         }
  1332.     }
  1333.     else if (almost_equals(c_token,"loc$ale")) {
  1334.         c_token++;
  1335.         if (END_OF_COMMAND) {
  1336.             set_locale("");
  1337.         } else if (isstring(c_token)) {
  1338.             char ss[MAX_ID_LEN+1];
  1339.             quote_str(ss,c_token,MAX_ID_LEN);
  1340.             set_locale(ss);
  1341.             ++c_token;
  1342.         } else {
  1343.             int_error("Expected string", c_token);
  1344.         }
  1345.     }
  1346.  
  1347. #define DO_ZEROAX(variable, string,neg) \
  1348. else if (almost_equals(c_token, string)) { \
  1349.    ++c_token; if (END_OF_COMMAND) variable=-1; \
  1350.    else { struct value a; variable=real(const_express(&a))-1; }\
  1351. } else if (almost_equals(c_token, neg)) { \
  1352.    ++c_token; variable=-3; \
  1353. }
  1354.  
  1355.  
  1356.     DO_ZEROAX(xzeroaxis, "xzero$axis", "noxzero$axis")
  1357.     DO_ZEROAX(yzeroaxis, "yzero$axis", "noyzero$axis")
  1358.     DO_ZEROAX(x2zeroaxis, "x2zero$axis", "nox2zero$axis")
  1359.     DO_ZEROAX(y2zeroaxis, "y2zero$axis", "noy2zero$axis")
  1360.  
  1361.     else if (almost_equals(c_token,"zeroa$xis")) {
  1362.         int line=-1;
  1363.         c_token++;
  1364.         if (!END_OF_COMMAND) {
  1365.             struct value a;
  1366.             line=real(const_express(&a))-1;
  1367.         }
  1368.         xzeroaxis =
  1369.         yzeroaxis = line;
  1370.     }
  1371.     else if (almost_equals(c_token,"nozero$axis")) {
  1372.         c_token++;
  1373.         xzeroaxis = -3;
  1374.         yzeroaxis = -3;
  1375.         x2zeroaxis = -3;
  1376.         y2zeroaxis = -3;
  1377.     } else if (almost_equals(c_token,"par$ametric")) {
  1378.         if (!parametric) {
  1379.            parametric = TRUE;
  1380.            if (!polar) { /* already done for polar */
  1381.                strcpy (dummy_var[0], "t");
  1382.                strcpy (dummy_var[1], "y");
  1383.                if (interactive)
  1384.                  (void) fprintf(stderr,"\n\tdummy variable is t for curves, u/v for surfaces\n");
  1385.             }
  1386.         }
  1387.         c_token++;
  1388.     }
  1389.     else if (almost_equals(c_token,"nopar$ametric")) {
  1390.         if (parametric) {
  1391.            parametric = FALSE;
  1392.            if (!polar) { /* keep t for polar */
  1393.                strcpy (dummy_var[0], "x");
  1394.                strcpy (dummy_var[1], "y");
  1395.                if (interactive)
  1396.                  (void) fprintf(stderr,"\n\tdummy variable is x for curves, x/y for surfaces\n");
  1397.             }
  1398.         }
  1399.         c_token++;
  1400.     }
  1401.     else if (almost_equals(c_token, "poi$ntsize")) {
  1402.         struct value a;
  1403.         c_token++;
  1404.         if (END_OF_COMMAND)
  1405.             pointsize = 1.0;
  1406.         else
  1407.             pointsize = real(const_express(&a));
  1408.         if(pointsize<=0) pointsize=1;
  1409.         if (term_init && term->set_pointsize)
  1410.             (*term->set_pointsize)(pointsize);
  1411.     }
  1412.     else if (almost_equals(c_token,"pol$ar")) {
  1413.         if (!polar) {
  1414.             if (!parametric) {
  1415.                 if (interactive)
  1416.                     (void) fprintf(stderr,"\n\tdummy variable is t for curves\n");
  1417.                 strcpy (dummy_var[0], "t");
  1418.             }
  1419.             polar = TRUE;
  1420.             if (autoscale_t) {
  1421.                 /* only if user has not set a range manually */
  1422.                 tmin = 0.0;
  1423.                 tmax = 2*Pi / ang2rad;  /* 360 if degrees, 2pi if radians */
  1424.             }
  1425.         }
  1426.         c_token++;
  1427.     }
  1428.     else if (almost_equals(c_token,"nopo$lar")) {
  1429.         if (polar) {
  1430.             polar = FALSE;
  1431.             if (parametric && autoscale_t) {
  1432.                 /* only if user has not set an explicit range */
  1433.                 tmin = -5.0;
  1434.                 tmax = 5.0;
  1435.             }
  1436.             if (!parametric) {
  1437.                 strcpy (dummy_var[0], "x");
  1438.                 if (interactive)
  1439.                     (void) fprintf(stderr,"\n\tdummy variable is x for curves\n");
  1440.             }
  1441.         
  1442.  
  1443.         }
  1444.         c_token++;
  1445.     }
  1446.     else if (almost_equals(c_token,"an$gles")) {
  1447.         c_token++;
  1448.         if (END_OF_COMMAND) {
  1449.         /* assuming same as defaults */
  1450.         angles_format = ANGLES_RADIANS;
  1451.         ang2rad=1;
  1452.         }
  1453.         else if (almost_equals(c_token, "r$adians")) {
  1454.         angles_format = ANGLES_RADIANS;
  1455.         c_token++;
  1456.         ang2rad=1;
  1457.         }
  1458.         else if (almost_equals(c_token, "d$egrees")) {
  1459.         angles_format = ANGLES_DEGREES;
  1460.         c_token++;
  1461.         ang2rad=DEG2RAD;
  1462.         }
  1463.         else
  1464.          int_error("expecting 'radians' or 'degrees'", c_token);
  1465.  
  1466.         if (polar && autoscale_t) {
  1467.         /* set trange if in polar mode and no explicit range */
  1468.         tmin=0;
  1469.         tmax=2*Pi/ang2rad;
  1470.         }
  1471.     }
  1472.  
  1473. #define GRID_MATCH(string, neg, mask) \
  1474. if (almost_equals(c_token, string)) { grid |= mask; ++c_token; } \
  1475. else if (almost_equals(c_token, neg)) { grid &= ~(mask); ++c_token; }
  1476.  
  1477.     else if (almost_equals(c_token,"g$rid")) {
  1478.                 c_token++;
  1479.         if (END_OF_COMMAND && !grid)
  1480.             grid = GRID_X|GRID_Y;
  1481.                 else while (!END_OF_COMMAND){
  1482.             GRID_MATCH("x$tics", "nox$tics", GRID_X)
  1483.             else GRID_MATCH("y$tics", "noy$tics", GRID_Y)
  1484.             else GRID_MATCH("z$tics", "noz$tics", GRID_Z)
  1485.             else GRID_MATCH("x2$tics", "nox2$tics", GRID_X2)
  1486.             else GRID_MATCH("y2$tics", "noy2$tics", GRID_Y2)
  1487.             else GRID_MATCH("mx$tics", "nomx$tics", GRID_MX)
  1488.             else GRID_MATCH("my$tics", "nomy$tics", GRID_MY)
  1489.             else GRID_MATCH("mz$tics", "nomz$tics", GRID_MZ)
  1490.             else GRID_MATCH("mx2$tics", "nomx2$tics", GRID_MX2)
  1491.             else GRID_MATCH("my2$tics", "nomy2$tics", GRID_MY2)
  1492.             else if (almost_equals(c_token,"po$lar")){
  1493.                 if (!grid) grid=GRID_X;
  1494.                                 c_token++;
  1495.                                 if (END_OF_COMMAND) {
  1496.                                     polar_grid_angle=30*DEG2RAD;
  1497.                                 } else {
  1498.                     /* get radial interval */
  1499.                                     struct value a;
  1500.                                     polar_grid_angle=ang2rad*real(const_express(&a));
  1501.                                 }
  1502.             } else if (almost_equals(c_token,"nopo$lar")){
  1503.                                 polar_grid_angle=0; /* not polar grid */
  1504.                                 c_token++;
  1505.             } else break; /* might be a linetype */
  1506.         }
  1507.         if (!END_OF_COMMAND) {
  1508.             struct value a;
  1509.             grid_linetype=real(const_express(&a))-1;
  1510.             if (!grid) grid = GRID_X|GRID_Y;
  1511.                 /* probably just  set grid <linetype> */
  1512.  
  1513.             if (END_OF_COMMAND) {
  1514.                 mgrid_linetype=grid_linetype;
  1515.             } else {
  1516.                 mgrid_linetype=real(const_express(&a))-1;
  1517.             }
  1518.  
  1519.             if (!grid) grid = GRID_X|GRID_Y;
  1520.                 /* probably just  set grid <linetype> */
  1521.         }
  1522.  
  1523.         
  1524.         }
  1525.     else if (almost_equals(c_token,"nog$rid")) {
  1526.         grid = GRID_OFF;
  1527.         c_token++;
  1528.     }
  1529.     else if (almost_equals(c_token,"su$rface")) {
  1530.         draw_surface = TRUE;
  1531.         c_token++;
  1532.     }
  1533.     else if (almost_equals(c_token,"nosu$rface")) {
  1534.         draw_surface = FALSE;
  1535.         c_token++;
  1536.     }
  1537.     else if (almost_equals(c_token,"bor$der")) {
  1538.         struct value a;
  1539.         c_token++;
  1540.         if(END_OF_COMMAND){
  1541.             draw_border = 31;
  1542.         } else {
  1543.             draw_border = (int)real(const_express(&a));
  1544.         }
  1545.     }
  1546.     else if (almost_equals(c_token,"k$ey")) {
  1547.         struct value a;
  1548.         c_token++;
  1549.         if (END_OF_COMMAND) {
  1550.             key = -1;
  1551.             key_vpos = TTOP;
  1552.             key_hpos = TRIGHT;
  1553.             key_just = JRIGHT;
  1554.         } 
  1555.         else {
  1556.             enum position_type default_scale=first_axes;
  1557.             while (!END_OF_COMMAND) {
  1558.                 if (almost_equals(c_token,"t$op")) {
  1559.                     key_vpos = TTOP;
  1560.                     key = -1;
  1561.                 } else if (almost_equals(c_token,"b$ottom")) {
  1562.                     key_vpos = TBOTTOM;
  1563.                     key = -1;
  1564.                 } else if (almost_equals(c_token,"l$eft")) {
  1565.                     key_hpos = TLEFT;
  1566.                     /* key_just = TRIGHT; */
  1567.                     key = -1;
  1568.                 } else if (almost_equals(c_token,"r$ight")) {
  1569.                     key_hpos = TRIGHT;
  1570.                     key = -1;
  1571.                 } else if (almost_equals(c_token,"u$nder") ||
  1572.                     almost_equals(c_token,"be$low")) {
  1573.                     key_vpos = TUNDER;
  1574.                     if (key_hpos == TOUT) key_hpos--;
  1575.                     key = -1;
  1576.                 } else if (almost_equals(c_token,"o$utside")) {
  1577.                     key_hpos = TOUT;
  1578.                     if (key_vpos == TUNDER) key_vpos--;
  1579.                     key = -1;
  1580.                 } else if (almost_equals(c_token,"L$eft")) {
  1581.                     /* key_hpos = TLEFT; */
  1582.                     key_just = JLEFT;
  1583.                     /* key = -1; */
  1584.                 } else if (almost_equals(c_token,"R$ight")) {
  1585.                     /* key_hpos = TLEFT; */
  1586.                     key_just = JRIGHT;
  1587.                     /* key = -1; */
  1588.                 } else if (almost_equals(c_token,"rev$erse")) {
  1589.                     key_reverse=TRUE;
  1590.                 } else if (almost_equals(c_token,"norev$erse")) {
  1591.                     key_reverse=FALSE;
  1592.                 } else if (almost_equals(c_token,"b$ox")) {
  1593.                     ++c_token;
  1594.                     if (END_OF_COMMAND)
  1595.                         key_box=-2;
  1596.                     else
  1597.                         key_box=real(const_express(&a))-1;
  1598.                     --c_token;  /* is incremented after loop */
  1599.                 } else if (almost_equals(c_token,"nob$ox")) {
  1600.                     key_box=-3;
  1601.                 } else if (almost_equals(c_token,"ti$tle")) {
  1602.                     if (isstring(c_token+1)) {
  1603.                         /* We have string specified - grab it. */
  1604.                         quote_str(key_title,++c_token, MAX_LINE_LEN);
  1605.                     }
  1606.                     else
  1607.                         key_title[0]=0;
  1608.                 } else {
  1609.                     default_scale = get_position(&key_user_pos, default_scale);
  1610.                     key = 1;
  1611.                     --c_token;  /* will be incremented again soon */
  1612.                 } 
  1613.                 c_token++;
  1614.              } 
  1615.         }
  1616.     }
  1617.     else if (almost_equals(c_token,"nok$ey")) {
  1618.         key = 0;
  1619.         c_token++;
  1620.     }
  1621.     else if (almost_equals(c_token,"tic$s")) {
  1622.         tic_in = TRUE;
  1623.         c_token++;
  1624.         if (almost_equals(c_token,"i$n")) {
  1625.             tic_in = TRUE;
  1626.             c_token++;
  1627.         }
  1628.         else if (almost_equals(c_token,"o$ut")) {
  1629.             tic_in = FALSE;
  1630.             c_token++;
  1631.         }
  1632.     }
  1633.      else if (almost_equals(c_token,"xda$ta")) {
  1634.      c_token++;
  1635.      if(END_OF_COMMAND) {
  1636.         datatype[FIRST_X_AXIS] = FALSE;
  1637.         /* eh ? - t and u have nothing to do with x */
  1638.         datatype[T_AXIS] = FALSE;
  1639.         datatype[U_AXIS] = FALSE;
  1640.      } else {
  1641.         if (almost_equals(c_token,"t$ime")) {
  1642.             datatype[FIRST_X_AXIS] = TIME;
  1643.             datatype[T_AXIS] = TIME;
  1644.             datatype[U_AXIS] = TIME;
  1645.         } else {
  1646.             datatype[FIRST_X_AXIS] = FALSE;
  1647.             datatype[T_AXIS] = FALSE;
  1648.             datatype[U_AXIS] = FALSE;
  1649.         }
  1650.         c_token++;
  1651.      }
  1652.      }
  1653.      else if (almost_equals(c_token,"yda$ta")) {
  1654.      c_token++;
  1655.      if(END_OF_COMMAND) {
  1656.         datatype[FIRST_Y_AXIS] = FALSE;
  1657.         datatype[V_AXIS] = FALSE;
  1658.      } else {
  1659.         if (almost_equals(c_token,"t$ime")) {
  1660.             datatype[FIRST_Y_AXIS] = TIME;
  1661.             datatype[V_AXIS] = TIME;
  1662.         } else {
  1663.             datatype[FIRST_Y_AXIS] = FALSE;
  1664.             datatype[V_AXIS] = FALSE;
  1665.         }
  1666.         c_token++;
  1667.      }
  1668.      }
  1669.      else if (almost_equals(c_token,"zda$ta")) {
  1670.      c_token++;
  1671.      if(END_OF_COMMAND) {
  1672.         datatype[FIRST_Z_AXIS] = FALSE;
  1673.      } else {
  1674.         if (almost_equals(c_token,"t$ime")) {
  1675.             datatype[FIRST_Z_AXIS] = TIME;
  1676.         } else {
  1677.             datatype[FIRST_Z_AXIS] = FALSE;
  1678.         }
  1679.         c_token++;
  1680.      }
  1681.      }
  1682.      else if (almost_equals(c_token,"x2da$ta")) {
  1683.      c_token++;
  1684.      if(END_OF_COMMAND) {
  1685.         datatype[SECOND_X_AXIS] = FALSE;
  1686.      } else {
  1687.         if (almost_equals(c_token,"t$ime")) {
  1688.             datatype[SECOND_X_AXIS] = TIME;
  1689.         } else {
  1690.             datatype[SECOND_X_AXIS] = FALSE;
  1691.         }
  1692.         c_token++;
  1693.      }
  1694.      }
  1695.      else if (almost_equals(c_token,"y2da$ta")) {
  1696.      c_token++;
  1697.      if(END_OF_COMMAND) {
  1698.         datatype[SECOND_Y_AXIS] = FALSE;
  1699.      } else {
  1700.         if (almost_equals(c_token,"t$ime")) {
  1701.             datatype[SECOND_Y_AXIS] = TIME;
  1702.         } else {
  1703.             datatype[SECOND_Y_AXIS] = FALSE;
  1704.         }
  1705.         c_token++;
  1706.      }
  1707.      }
  1708.  
  1709. /* to save duplicating code for x/y/z/x2/y2, make a macro
  1710.  * (should perhaps be a function ?)
  1711.  * unfortunately, string concatenation is not supported on all compilers :-(
  1712.  */
  1713.  
  1714. #define PROCESS_TIC_COMMANDS(TICS, MTICS, FREQ, TICDEF, AXIS, STRING, NOSTRING, MONTH, DAY, MINISTRING, NOMINI) \
  1715. else if (almost_equals(c_token, STRING)) { \
  1716.  if (almost_equals(++c_token, "ax$is")) {\
  1717.   TICS &= ~TICS_ON_BORDER; TICS |= TICS_ON_AXIS; ++c_token;\
  1718.    /* set tics to border if border specified or they were off, else leave (maybe axis) */\
  1719.  } else if ( (almost_equals(c_token, "bo$rder") && ++c_token) || !TICS) { \
  1720.   TICS &= ~TICS_ON_AXIS; TICS |= TICS_ON_BORDER;\
  1721.  }\
  1722.  if (almost_equals(c_token, "mi$rror")) {\
  1723.   TICS |= TICS_MIRROR; ++c_token; \
  1724.  } else if (almost_equals(c_token, "nomi$rror")) {\
  1725.   TICS &= ~TICS_MIRROR; ++c_token; \
  1726.  }\
  1727.  if (END_OF_COMMAND) { /* reset to default */\
  1728.   if (TICDEF.type == TIC_USER) { free_marklist(TICDEF.def.user); TICDEF.def.user = NULL; }\
  1729.   TICDEF.type = TIC_COMPUTED;\
  1730.  } else load_tics(AXIS,&TICDEF);\
  1731. } else if (almost_equals(c_token,NOSTRING)) {\
  1732.  TICS = NO_TICS; c_token++;\
  1733. } else if (almost_equals(c_token,MONTH)) {\
  1734.   if (TICDEF.type == TIC_USER) { free_marklist(TICDEF.def.user); TICDEF.def.user = NULL; }\
  1735.   TICDEF.type = TIC_MONTH; ++c_token;\
  1736. } else if (almost_equals(c_token,DAY)) {\
  1737.   if (TICDEF.type == TIC_USER) { free_marklist(TICDEF.def.user); TICDEF.def.user = NULL; }\
  1738.   TICDEF.type = TIC_DAY; ++c_token; \
  1739. } else if (almost_equals(c_token,MINISTRING)) { /* eg mxtics */\
  1740.  struct value freq;\
  1741.  c_token++; \
  1742.  if (END_OF_COMMAND) { MTICS=MINI_AUTO; }\
  1743.  else if (almost_equals(c_token, "def$ault")) {\
  1744.   MTICS=MINI_DEFAULT; ++c_token; \
  1745.  } else { \
  1746.   FREQ=real(const_express(&freq)); FREQ=floor(FREQ);\
  1747.   MTICS=MINI_USER; \
  1748. }} else if (almost_equals(c_token,NOMINI)) {\
  1749.   MTICS = FALSE;  c_token++;\
  1750. }
  1751.  
  1752.  
  1753. PROCESS_TIC_COMMANDS(x2tics,mx2tics,mx2tfreq,x2ticdef,SECOND_X_AXIS,"x2t$ics","nox2t$ics","x2m$tics","x2d$tics","mx2t$ics","nomx2t$ics")
  1754. PROCESS_TIC_COMMANDS(y2tics,my2tics,my2tfreq,y2ticdef,SECOND_Y_AXIS,"y2t$ics","noy2t$ics","y2m$tics","y2d$tics","my2t$ics","nomy2t$ics" )
  1755. PROCESS_TIC_COMMANDS(xtics, mxtics, mxtfreq, xticdef, FIRST_X_AXIS,"xt$ics","noxt$ics","xm$tics","xd$tics","mxt$ics","nomxt$ics")
  1756. PROCESS_TIC_COMMANDS(ytics, mytics, mytfreq, yticdef, FIRST_Y_AXIS,"yt$ics","noyt$ics","ym$tics","yd$tics","myt$ics","nomyt$ics")
  1757. PROCESS_TIC_COMMANDS(ztics, mztics, mztfreq, zticdef, FIRST_Z_AXIS,"zt$ics","nozt$ics","zm$tics","zd$tics","mzt$ics","nomzt$ics")
  1758.  
  1759.     else if (almost_equals(c_token,"ticsl$evel")) {
  1760.         double tlvl;
  1761.         struct value a;
  1762.  
  1763.         c_token++;
  1764.         /* is datatype 'time' relevant here ? */
  1765.         tlvl = real(const_express(&a));
  1766.         ticslevel = tlvl;
  1767.     }
  1768.  
  1769. #define PROCESS_MARGIN(variable, string) \
  1770. else if (almost_equals(c_token,string)) {\
  1771.  ++c_token; if (END_OF_COMMAND) variable=-1;\
  1772.  else { struct value a; variable=real(const_express(&a)); } \
  1773. }
  1774.  
  1775.     PROCESS_MARGIN(lmargin, "lmar$gin")
  1776.     PROCESS_MARGIN(bmargin, "bmar$gin")
  1777.     PROCESS_MARGIN(rmargin, "rmar$gin")
  1778.     PROCESS_MARGIN(tmargin, "tmar$gin")
  1779.  
  1780.     else
  1781.     return(FALSE);    /* no command match */
  1782.  
  1783.     return(TRUE);
  1784. }
  1785.  
  1786.  
  1787.  
  1788. /* return TRUE if a command match, FALSE if not */
  1789. static TBOOLEAN
  1790. set_three()
  1791. {
  1792.      if (almost_equals(c_token,"sa$mples")) {
  1793.         register int tsamp1, tsamp2;
  1794.         struct value a;
  1795.  
  1796.         c_token++;
  1797.         tsamp1 = (int)magnitude(const_express(&a));
  1798.         tsamp2 = tsamp1;
  1799.         if (!END_OF_COMMAND) {
  1800.             if (!equals(c_token,","))
  1801.                 int_error("',' expected",c_token);
  1802.             c_token++;
  1803.             tsamp2 = (int)magnitude(const_express(&a));
  1804.         }
  1805.         if (tsamp1 < 2 || tsamp2 < 2)
  1806.             int_error("sampling rate must be > 1; sampling unchanged",
  1807.                 c_token);
  1808.         else {
  1809.                 extern struct surface_points *first_3dplot;
  1810.             register struct surface_points *f_3dp = first_3dplot;
  1811.  
  1812.             first_3dplot = NULL;
  1813.             sp_free(f_3dp);
  1814.  
  1815.             samples = tsamp1;
  1816.             samples_1 = tsamp1;
  1817.             samples_2 = tsamp2;
  1818.         }
  1819.     }
  1820.     else if (almost_equals(c_token,"isosa$mples")) {
  1821.         register int tsamp1, tsamp2;
  1822.         struct value a;
  1823.  
  1824.         c_token++;
  1825.         tsamp1 = (int)magnitude(const_express(&a));
  1826.         tsamp2 = tsamp1;
  1827.         if (!END_OF_COMMAND) {
  1828.             if (!equals(c_token,","))
  1829.                 int_error("',' expected",c_token);
  1830.             c_token++;
  1831.             tsamp2 = (int)magnitude(const_express(&a));
  1832.         }
  1833.         if (tsamp1 < 2 || tsamp2 < 2)
  1834.             int_error("sampling rate must be > 1; sampling unchanged",
  1835.                 c_token);
  1836.         else {
  1837.                 extern struct curve_points *first_plot;
  1838.                 extern struct surface_points *first_3dplot;
  1839.             register struct curve_points *f_p = first_plot;
  1840.             register struct surface_points *f_3dp = first_3dplot;
  1841.  
  1842.             first_plot = NULL;
  1843.             first_3dplot = NULL;
  1844.             cp_free(f_p);
  1845.             sp_free(f_3dp);
  1846.  
  1847.             iso_samples_1 = tsamp1;
  1848.             iso_samples_2 = tsamp2;
  1849.         }
  1850.     }
  1851.     else if (almost_equals(c_token,"si$ze")) {
  1852.         struct value s;
  1853.         c_token++;
  1854.         if (END_OF_COMMAND) {
  1855.             xsize = 1.0;
  1856.             ysize = 1.0;
  1857.         } else {
  1858.                 if (almost_equals(c_token, "sq$uare")) {
  1859.                     square=TRUE;
  1860.                     ++c_token;
  1861.                 } else if (almost_equals(c_token,"nosq$uare")) {
  1862.                     square=FALSE;
  1863.                     ++c_token;
  1864.                 }
  1865.                 if (!END_OF_COMMAND) {
  1866.                     xsize=real(const_express(&s));
  1867.                     if (equals(c_token,",")) {
  1868.                         c_token++;
  1869.                         ysize=real(const_express(&s));
  1870.                     } else {
  1871.                         ysize=xsize;
  1872.                     }
  1873.                 }
  1874.             }
  1875.         } 
  1876.       else if (almost_equals(c_token,"ticsc$ale")) {
  1877.                 struct value tscl;
  1878.                 c_token++;
  1879.                 if (END_OF_COMMAND) {
  1880.                         ticscale = 1.0;
  1881.             miniticscale = 0.5;
  1882.                 } else {
  1883.                         ticscale=real(const_express(&tscl));
  1884.             if (END_OF_COMMAND) {
  1885.                 miniticscale=ticscale*0.5;
  1886.             } else {
  1887.                 miniticscale=real(const_express(&tscl));
  1888.             }
  1889.                 }
  1890.         }
  1891.     else if (almost_equals(c_token,"t$erminal")) {
  1892.      if (multiplot) {
  1893.          fprintf(stderr,"You can't change the terminal in multiplotmode\n");
  1894.          c_token++;
  1895.        } else {
  1896.         c_token++;
  1897.         if (END_OF_COMMAND) {
  1898.             list_terms();
  1899.             screen_ok = FALSE;
  1900.         }
  1901.         else {
  1902.             if (term && term_init) {
  1903.                 (*term->reset)();
  1904.                 (void) fflush(outfile);
  1905.                 term=0; term_init=0; /* in case set_term() fails */
  1906.             }
  1907.             term = set_term(c_token);
  1908.             c_token++;
  1909.  
  1910.             /* get optional mode parameters */
  1911.             if (term)
  1912.                 (*term->options)();
  1913.             if (interactive && *term_options)
  1914.                 fprintf(stderr,"Options are '%s'\n",term_options);
  1915.         }
  1916.     }
  1917.     }
  1918.     else if (almost_equals(c_token,"tim$estamp")) {
  1919.         c_token++;
  1920.         if (END_OF_COMMAND || !isstring(c_token))
  1921.             strcpy(timelabel.text, DEFAULT_TIMESTAMP_FORMAT);
  1922.  
  1923.         if (!END_OF_COMMAND) {
  1924.             struct value a;
  1925.  
  1926.             if (isstring(c_token)) {
  1927.                 /* we have a format string */
  1928.                 quote_str(timelabel.text, c_token, MAX_LINE_LEN);
  1929.                 ++c_token;
  1930.             } else {
  1931.                 strcpy(timelabel.text, DEFAULT_TIMESTAMP_FORMAT);
  1932.             }
  1933.             /* We have x,y offsets specified */
  1934.             if (!END_OF_COMMAND && !equals(c_token,","))
  1935.                 timelabel.xoffset = real(const_express(&a));
  1936.             if (!END_OF_COMMAND && equals(c_token,",")) {
  1937.                 c_token++;
  1938.                 timelabel.yoffset = real(const_express(&a));
  1939.             }
  1940.             if (!END_OF_COMMAND && isstring(c_token)) {
  1941.                 quote_str(timelabel.font, c_token, MAX_LINE_LEN);
  1942.                 ++c_token;
  1943.             } else {
  1944.                 *timelabel.font = 0;
  1945.             }
  1946.         }
  1947.     }
  1948.     else if (almost_equals(c_token,"not$ime")) {
  1949.         *timelabel.text = 0;
  1950.         c_token++;
  1951.     }
  1952.     else if (almost_equals(c_token,"vi$ew")) {
  1953.         int i;
  1954.         TBOOLEAN was_comma = TRUE;
  1955.         double local_vals[4];
  1956.         struct value a;
  1957.  
  1958.         local_vals[0] = surface_rot_x;
  1959.         local_vals[1] = surface_rot_z;
  1960.         local_vals[2] = surface_scale;
  1961.         local_vals[3] = surface_zscale;
  1962.         c_token++;
  1963.         for (i = 0; i < 4 && !(END_OF_COMMAND);) {
  1964.             if (equals(c_token,",")) {
  1965.                 if (was_comma) i++;
  1966.                 was_comma = TRUE;
  1967.                 c_token++;
  1968.             }
  1969.             else {
  1970.                 if (!was_comma)
  1971.                     int_error("',' expected",c_token);
  1972.                 local_vals[i] = real(const_express(&a));
  1973.                 i++;
  1974.                 was_comma = FALSE;
  1975.             }
  1976.         }
  1977.  
  1978.         if (local_vals[0] < 0 || local_vals[0] > 180)
  1979.             int_error("rot_x must be in [0:180] degrees range; view unchanged",
  1980.                   c_token);
  1981.         if (local_vals[1] < 0 || local_vals[1] > 360)
  1982.             int_error("rot_z must be in [0:360] degrees range; view unchanged",
  1983.                   c_token);
  1984.         if (local_vals[2] < 1e-6)
  1985.             int_error("scale must be > 0; view unchanged", c_token);
  1986.         if (local_vals[3] < 1e-6)
  1987.             int_error("zscale must be > 0; view unchanged", c_token);
  1988.  
  1989.         surface_rot_x = local_vals[0];
  1990.         surface_rot_z = local_vals[1];
  1991.         surface_scale = local_vals[2];
  1992.         surface_zscale = local_vals[3];
  1993.     }
  1994.  
  1995. /* to save replicated code, define a macro */
  1996. #define PROCESS_RANGE(AXIS,STRING, MIN, MAX, AUTO) \
  1997. else if (almost_equals(c_token, STRING)) { \
  1998.  if (!equals(++c_token,"[")) int_error("expecting '['",c_token); \
  1999.  c_token++; \
  2000.  AUTO = load_range(AXIS,&MIN,&MAX,AUTO); \
  2001.  if (!equals(c_token,"]")) int_error("expecting ']'",c_token); \
  2002.  c_token++; \
  2003.  if (almost_equals(c_token, "rev$erse")) { \
  2004.    ++c_token; range_flags[AXIS] |= RANGE_REVERSE;\
  2005.  } else if (almost_equals(c_token, "norev$erse")) { \
  2006.    ++c_token; range_flags[AXIS] &= ~RANGE_REVERSE;\
  2007.  } if (almost_equals(c_token, "wr$iteback")) { \
  2008.    ++c_token; range_flags[AXIS] |= RANGE_WRITEBACK;\
  2009.  } else if (almost_equals(c_token, "nowri$teback")) { \
  2010.    ++c_token; range_flags[AXIS] &= ~RANGE_WRITEBACK;\
  2011. }}
  2012.     PROCESS_RANGE(R_AXIS, "rr$ange", rmin, rmax, autoscale_r)
  2013.     PROCESS_RANGE(T_AXIS, "tr$ange", tmin, tmax, autoscale_t)
  2014.     PROCESS_RANGE(U_AXIS, "ur$ange", umin, umax, autoscale_u)
  2015.     PROCESS_RANGE(V_AXIS, "vr$ange", vmin, vmax, autoscale_v)
  2016.     PROCESS_RANGE(FIRST_X_AXIS, "xr$ange", xmin, xmax, autoscale_x)
  2017.     PROCESS_RANGE(FIRST_Y_AXIS, "yr$ange", ymin, ymax, autoscale_y)
  2018.     PROCESS_RANGE(FIRST_Z_AXIS, "zr$ange", zmin, zmax, autoscale_z)
  2019.     PROCESS_RANGE(SECOND_X_AXIS, "x2r$ange", x2min, x2max, autoscale_x2)
  2020.     PROCESS_RANGE(SECOND_Y_AXIS, "y2r$ange", y2min, y2max, autoscale_y2)
  2021.  
  2022.     else if (almost_equals(c_token,"z$ero")) {
  2023.         struct value a;
  2024.         c_token++;
  2025.         zero = magnitude(const_express(&a));
  2026.     }
  2027.     else if (almost_equals(c_token,"multi$plot")) {
  2028.       if (multiplot && term_graphics) {
  2029.         (*term->text)();
  2030.         term_graphics = FALSE;
  2031.         (void) fflush(outfile);
  2032.       } else {        
  2033.         multiplot = TRUE;
  2034.         if (!term_init) {
  2035.           (*term->init)();
  2036.           term_init = TRUE;
  2037.         }
  2038.         (*term->graphics)();
  2039.         term_graphics=TRUE;
  2040.       }
  2041.       c_token++;
  2042.     }
  2043.     else if (almost_equals(c_token,"nomulti$plot")) {
  2044.       if (term_graphics) {
  2045.            if (term_suspended && term->resume)
  2046.                (*term->resume)();
  2047.            term_suspended = FALSE;
  2048.         (*term->text)();
  2049.         (void) fflush(outfile);
  2050.         term_graphics=FALSE;
  2051.       }
  2052.         multiplot = FALSE;
  2053.         c_token++;
  2054.     }
  2055.     else
  2056.         return(FALSE);    /* no command match */
  2057.     return(TRUE);
  2058. }
  2059.  
  2060. /*********** Support functions for set_command ***********/
  2061.  
  2062. /* process a 'set {x/y/z}label command */
  2063. /* set {x/y/z}label {label_text} {x}{,y} */
  2064. static void set_xyzlabel(label)
  2065. label_struct *label;
  2066. {
  2067.     c_token++;
  2068.     if (END_OF_COMMAND) {    /* no label specified */
  2069.         *label->text = '\0';
  2070.         return;
  2071.     }
  2072.     
  2073.     if (isstring(c_token)) {
  2074.         /* We have string specified - grab it. */
  2075.         quote_str(label->text,c_token, MAX_LINE_LEN);
  2076.         c_token++;
  2077.     }
  2078.  
  2079.     if (END_OF_COMMAND)
  2080.         return;
  2081.  
  2082.     if (!isstring(c_token)) {
  2083.         /* We have x,y offsets specified */
  2084.         struct value a;
  2085.         if (!equals(c_token,","))
  2086.             label->xoffset = real(const_express(&a));
  2087.  
  2088.         if (END_OF_COMMAND)
  2089.             return;
  2090.  
  2091.         if (equals(c_token,",")) {
  2092.                 c_token++;
  2093.                 label->yoffset = real(const_express(&a));
  2094.         }
  2095.     }
  2096.  
  2097.     if (END_OF_COMMAND)
  2098.         return;
  2099.  
  2100.     if (!isstring(c_token))
  2101.         int_error("Expected font", c_token);
  2102.  
  2103.     quote_str(label->font,c_token, MAX_LINE_LEN);
  2104.     c_token++;
  2105. }
  2106.  
  2107. /* process a 'set label' command */
  2108. /* set label {tag} {label_text} {at x,y} {pos} {font name,size} */
  2109. /* Entry font added by DJL */
  2110. static void
  2111. set_label()
  2112. {
  2113.     struct value a;
  2114.     struct text_label *this_label = NULL;
  2115.     struct text_label *new_label = NULL;
  2116.     struct text_label *prev_label = NULL;
  2117.     struct position pos;
  2118.     char text[MAX_LINE_LEN+1],font[MAX_LINE_LEN+1];
  2119.     enum JUSTIFY just=LEFT;
  2120.     int tag;
  2121.     TBOOLEAN set_text, set_position, set_just=FALSE, set_font;
  2122.  
  2123.     /* get tag */
  2124.     if (!END_OF_COMMAND 
  2125.        && !isstring(c_token) 
  2126.        && !equals(c_token, "at")
  2127.        && !equals(c_token, "left")
  2128.        && !equals(c_token, "center")
  2129.        && !equals(c_token, "centre")
  2130.        && !equals(c_token, "right")
  2131.        && !equals(c_token, "font")) {
  2132.        /* must be a tag expression! */
  2133.        tag = (int)real(const_express(&a));
  2134.        if (tag <= 0)
  2135.         int_error("tag must be > zero", c_token);
  2136.     } else
  2137.      tag = assign_label_tag(); /* default next tag */
  2138.      
  2139.     /* get text */
  2140.     if (!END_OF_COMMAND && isstring(c_token)) {
  2141.        /* get text */
  2142.        quote_str(text, c_token, MAX_LINE_LEN);
  2143.        c_token++;
  2144.        set_text = TRUE;
  2145.     } else {
  2146.        text[0] = '\0';        /* default no text */
  2147.        set_text = FALSE;
  2148.     }
  2149.      
  2150.     /* get justification - what the heck, let him put it here */
  2151.     if (!END_OF_COMMAND && !equals(c_token, "at") && !equals(c_token, "font")) {
  2152.        if (almost_equals(c_token,"l$eft")) {
  2153.           just = LEFT;
  2154.        }
  2155.        else if (almost_equals(c_token,"c$entre")
  2156.               || almost_equals(c_token,"c$enter")) {
  2157.           just = CENTRE;
  2158.        }
  2159.        else if (almost_equals(c_token,"r$ight")) {
  2160.           just = RIGHT;
  2161.        }
  2162.        else
  2163.         int_error("bad syntax in set label", c_token);
  2164.        c_token++;
  2165.        set_just = TRUE;
  2166.     }
  2167.  
  2168.     /* get position */
  2169.     if (!END_OF_COMMAND && equals(c_token, "at")) {
  2170.        c_token++;
  2171.  
  2172.         get_position(&pos, first_axes);
  2173.        set_position = TRUE;
  2174.     } else {
  2175.         pos.x = pos.y = pos.z = 0;
  2176.         pos.scalex=pos.scaley=pos.scalez=first_axes;
  2177.        set_position = FALSE;
  2178.     }
  2179.  
  2180.     /* get justification */
  2181.     if (!END_OF_COMMAND && !equals(c_token, "font")) {
  2182.        if (set_just)
  2183.         int_error("only one justification is allowed", c_token);
  2184.        if (almost_equals(c_token,"l$eft")) {
  2185.           just = LEFT;
  2186.        }
  2187.        else if (almost_equals(c_token,"c$entre")
  2188.               || almost_equals(c_token,"c$enter")) {
  2189.           just = CENTRE;
  2190.        }
  2191.        else if (almost_equals(c_token,"r$ight")) {
  2192.           just = RIGHT;
  2193.        }
  2194.        else
  2195.         int_error("bad syntax in set label", c_token);
  2196.        c_token++;
  2197.        set_just = TRUE;
  2198.     } 
  2199.  
  2200.     /* get font */
  2201.     font[0]='\0'; set_font = FALSE;
  2202.     if (!END_OF_COMMAND && equals(c_token, "font")) {
  2203.        c_token++;
  2204.        if (END_OF_COMMAND)
  2205.         int_error("font name and size expected", c_token);
  2206.            if (isstring(c_token)) {
  2207.             quote_str(font, c_token, MAX_ID_LEN);
  2208.                 /* get 'name,size', no further check */
  2209.                 set_font = TRUE;
  2210.            }
  2211.        else
  2212.         int_error("'fontname,fontsize' expected", c_token);
  2213.            c_token++;
  2214.     } /* Entry font added by DJL */
  2215.  
  2216.     if (!END_OF_COMMAND)
  2217.      int_error("extraenous or out-of-order arguments in set label", c_token);
  2218.  
  2219.     /* OK! add label */
  2220.     if (first_label != NULL) { /* skip to last label */
  2221.        for (this_label = first_label; this_label != NULL ; 
  2222.            prev_label = this_label, this_label = this_label->next)
  2223.         /* is this the label we want? */
  2224.         if (tag <= this_label->tag)
  2225.           break;
  2226.     }
  2227.     if (this_label != NULL && tag == this_label->tag) {
  2228.        /* changing the label */
  2229.        if (set_position) {
  2230.           this_label->place=pos;
  2231.        }
  2232.        if (set_text)
  2233.         (void) strcpy(this_label->text, text);
  2234.        if (set_just)
  2235.         this_label->pos = just;
  2236.        if (set_font)
  2237.                 (void) strcpy(this_label->font, font);
  2238.     } else {
  2239.        /* adding the label */
  2240.        new_label = (struct text_label *) 
  2241.         alloc ( (unsigned long) sizeof(struct text_label), "label");
  2242.        if (prev_label != NULL)
  2243.         prev_label->next = new_label; /* add it to end of list */
  2244.        else 
  2245.         first_label = new_label; /* make it start of list */
  2246.        new_label->tag = tag;
  2247.        new_label->next = this_label;
  2248.        new_label->place=pos;
  2249.        (void) strcpy(new_label->text, text);
  2250.        new_label->pos = just;
  2251.            (void) strcpy(new_label->font, font);
  2252.     }
  2253. } /* Entry font added by DJL */
  2254.  
  2255. /* process 'set nolabel' command */
  2256. /* set nolabel {tag} */
  2257. static void
  2258. set_nolabel()
  2259. {
  2260.     struct value a;
  2261.     struct text_label *this_label;
  2262.     struct text_label *prev_label; 
  2263.     int tag;
  2264.  
  2265.     if (END_OF_COMMAND) {
  2266.        /* delete all labels */
  2267.        while (first_label != NULL)
  2268.         delete_label((struct text_label *)NULL,first_label);
  2269.     }
  2270.     else {
  2271.        /* get tag */
  2272.        tag = (int)real(const_express(&a));
  2273.        if (!END_OF_COMMAND)
  2274.         int_error("extraneous arguments to set nolabel", c_token);
  2275.        for (this_label = first_label, prev_label = NULL;
  2276.            this_label != NULL;
  2277.            prev_label = this_label, this_label = this_label->next) {
  2278.           if (this_label->tag == tag) {
  2279.              delete_label(prev_label,this_label);
  2280.              return;        /* exit, our job is done */
  2281.           }
  2282.        }
  2283.        int_error("label not found", c_token);
  2284.     }
  2285. }
  2286.  
  2287. /* assign a new label tag */
  2288. /* labels are kept sorted by tag number, so this is easy */
  2289. static int                /* the lowest unassigned tag number */
  2290. assign_label_tag()
  2291. {
  2292.     struct text_label *this_label;
  2293.     int last = 0;            /* previous tag value */
  2294.  
  2295.     for (this_label = first_label; this_label != NULL;
  2296.         this_label = this_label->next)
  2297.      if (this_label->tag == last+1)
  2298.        last++;
  2299.      else
  2300.        break;
  2301.     
  2302.     return (last+1);
  2303. }
  2304.  
  2305. /* delete label from linked list started by first_label.
  2306.  * called with pointers to the previous label (prev) and the 
  2307.  * label to delete (this).
  2308.  * If there is no previous label (the label to delete is
  2309.  * first_label) then call with prev = NULL.
  2310.  */
  2311. static void
  2312. delete_label(prev,this)
  2313.     struct text_label *prev, *this;
  2314. {
  2315.     if (this!=NULL)    {        /* there really is something to delete */
  2316.        if (prev!=NULL)        /* there is a previous label */
  2317.         prev->next = this->next; 
  2318.        else                /* this = first_label so change first_label */
  2319.         first_label = this->next;
  2320.        free((char *)this);
  2321.     }
  2322. }
  2323.  
  2324.  
  2325. /* process a 'set arrow' command */
  2326. /* set arrow {tag} {from x,y} {to x,y} {{no}head} */
  2327. static void
  2328. set_arrow()
  2329. {
  2330.     struct value a;
  2331.     struct arrow_def *this_arrow = NULL;
  2332.     struct arrow_def *new_arrow = NULL;
  2333.     struct arrow_def *prev_arrow = NULL;
  2334.     struct position spos, epos;
  2335.     int axes=FIRST_AXES;
  2336.     int linetype=1;
  2337.     int tag;
  2338.     TBOOLEAN set_start, set_end, head = 1, set_axes=0, set_line=0;
  2339.     enum position_type pos_type=first_axes;
  2340.  
  2341.     /* get tag */
  2342.     if (!END_OF_COMMAND 
  2343.        && !equals(c_token, "from")
  2344.        && !equals(c_token, "to")
  2345.        && !equals(c_token, "first")
  2346.        && !equals(c_token, "second")) {
  2347.        /* must be a tag expression! */
  2348.        tag = (int)real(const_express(&a));
  2349.        if (tag <= 0)
  2350.         int_error("tag must be > zero", c_token);
  2351.     } else
  2352.      tag = assign_arrow_tag(); /* default next tag */
  2353.  
  2354.     if (!END_OF_COMMAND && equals(c_token, "first")) {
  2355.         ++c_token;
  2356.         axes=FIRST_AXES;
  2357.         set_axes=1;
  2358.     } else if (!END_OF_COMMAND && equals(c_token, "second")) {
  2359.         ++c_token;
  2360.         axes=SECOND_AXES;
  2361.         set_axes=1;
  2362.     }
  2363.     /* get start position */
  2364.     if (!END_OF_COMMAND && equals(c_token, "from")) {
  2365.        c_token++;
  2366.        if (END_OF_COMMAND)
  2367.         int_error("start coordinates expected", c_token);
  2368.        /* get coordinates */
  2369.         pos_type=get_position(&spos, pos_type);
  2370.        set_start = TRUE;
  2371.     } else {
  2372.         spos.x=spos.y=spos.z=0;
  2373.         spos.scalex=spos.scaley=spos.scalez=first_axes;
  2374.        set_start = FALSE;
  2375.     }
  2376.  
  2377.     /* get end position */
  2378.     if (!END_OF_COMMAND && equals(c_token, "to")) {
  2379.        c_token++;
  2380.        if (END_OF_COMMAND)
  2381.         int_error("end coordinates expected", c_token);
  2382.        /* get coordinates */
  2383.         pos_type=get_position(&epos, pos_type);
  2384.        set_end = TRUE;
  2385.     } else {
  2386.         epos.x=epos.y=epos.z=0;
  2387.         epos.scalex=epos.scaley=epos.scalez=first_axes;
  2388.        set_end = FALSE;
  2389.     }
  2390.  
  2391.     /* get start position - what the heck, either order is ok */
  2392.     if (!END_OF_COMMAND && equals(c_token, "from")) {
  2393.        if (set_start)
  2394.         int_error("only one 'from' is allowed", c_token);
  2395.        c_token++;
  2396.        if (END_OF_COMMAND)
  2397.         int_error("start coordinates expected", c_token);
  2398.        /* get coordinates */
  2399.         pos_type=get_position(&spos,pos_type);
  2400.        set_start = TRUE;
  2401.     }
  2402.  
  2403.     if (!END_OF_COMMAND && equals(c_token, "nohead")) {
  2404.        c_token++;
  2405.            head = 0;
  2406.     }
  2407.  
  2408.     if (!END_OF_COMMAND && equals(c_token, "head")) {
  2409.        c_token++;
  2410.            head = 1;
  2411.     }
  2412.  
  2413.     if (!END_OF_COMMAND) {
  2414.         struct value a;
  2415.         linetype=real(const_express(&a));
  2416.         set_line=1;
  2417.     }
  2418.     
  2419.     if (!END_OF_COMMAND)
  2420.      int_error("extraneous or out-of-order arguments in set arrow", c_token);
  2421.  
  2422.     /* OK! add arrow */
  2423.     if (first_arrow != NULL) { /* skip to last arrow */
  2424.        for (this_arrow = first_arrow; this_arrow != NULL ; 
  2425.            prev_arrow = this_arrow, this_arrow = this_arrow->next)
  2426.         /* is this the arrow we want? */
  2427.         if (tag <= this_arrow->tag)
  2428.           break;
  2429.     }
  2430.     if (this_arrow != NULL && tag == this_arrow->tag) {
  2431.        /* changing the arrow */
  2432.        if (set_start) {
  2433.           this_arrow->start=spos;
  2434.        }
  2435.        if (set_end) {
  2436.           this_arrow->end=epos;
  2437.        }
  2438.        this_arrow->head = head;
  2439.        if (set_line) this_arrow->line=linetype;
  2440.     } else {
  2441.        /* adding the arrow */
  2442.        new_arrow = (struct arrow_def *) 
  2443.         alloc ( (unsigned long) sizeof(struct arrow_def), "arrow");
  2444.        if (prev_arrow != NULL)
  2445.         prev_arrow->next = new_arrow; /* add it to end of list */
  2446.        else 
  2447.         first_arrow = new_arrow; /* make it start of list */
  2448.        new_arrow->tag = tag;
  2449.        new_arrow->next = this_arrow;
  2450.        new_arrow->start=spos;
  2451.        new_arrow->end=epos;
  2452.        new_arrow->head = head;
  2453.        new_arrow->line=linetype;
  2454.     }
  2455. }
  2456.  
  2457. /* process 'set noarrow' command */
  2458. /* set noarrow {tag} */
  2459. static void
  2460. set_noarrow()
  2461. {
  2462.     struct value a;
  2463.     struct arrow_def *this_arrow;
  2464.     struct arrow_def *prev_arrow; 
  2465.     int tag;
  2466.  
  2467.     if (END_OF_COMMAND) {
  2468.        /* delete all arrows */
  2469.        while (first_arrow != NULL)
  2470.         delete_arrow((struct arrow_def *)NULL,first_arrow);
  2471.     }
  2472.     else {
  2473.        /* get tag */
  2474.        tag = (int)real(const_express(&a));
  2475.        if (!END_OF_COMMAND)
  2476.         int_error("extraneous arguments to set noarrow", c_token);
  2477.        for (this_arrow = first_arrow, prev_arrow = NULL;
  2478.            this_arrow != NULL;
  2479.            prev_arrow = this_arrow, this_arrow = this_arrow->next) {
  2480.           if (this_arrow->tag == tag) {
  2481.              delete_arrow(prev_arrow,this_arrow);
  2482.              return;        /* exit, our job is done */
  2483.           }
  2484.        }
  2485.        int_error("arrow not found", c_token);
  2486.     }
  2487. }
  2488.  
  2489. /* assign a new arrow tag */
  2490. /* arrows are kept sorted by tag number, so this is easy */
  2491. static int                /* the lowest unassigned tag number */
  2492. assign_arrow_tag()
  2493. {
  2494.     struct arrow_def *this_arrow;
  2495.     int last = 0;            /* previous tag value */
  2496.  
  2497.     for (this_arrow = first_arrow; this_arrow != NULL;
  2498.         this_arrow = this_arrow->next)
  2499.      if (this_arrow->tag == last+1)
  2500.        last++;
  2501.      else
  2502.        break;
  2503.  
  2504.     return (last+1);
  2505. }
  2506.  
  2507. /* delete arrow from linked list started by first_arrow.
  2508.  * called with pointers to the previous arrow (prev) and the 
  2509.  * arrow to delete (this).
  2510.  * If there is no previous arrow (the arrow to delete is
  2511.  * first_arrow) then call with prev = NULL.
  2512.  */
  2513. static void
  2514. delete_arrow(prev,this)
  2515.     struct arrow_def *prev, *this;
  2516. {
  2517.     if (this!=NULL)    {        /* there really is something to delete */
  2518.        if (prev!=NULL)        /* there is a previous arrow */
  2519.         prev->next = this->next; 
  2520.        else                /* this = first_arrow so change first_arrow */
  2521.         first_arrow = this->next;
  2522.        free((char *)this);
  2523.     }
  2524. }
  2525.  
  2526.  
  2527. enum PLOT_STYLE            /* not static; used by command.c */
  2528. get_style()
  2529. {
  2530. register enum PLOT_STYLE ps;
  2531.  
  2532.     c_token++;
  2533.     if (almost_equals(c_token,"l$ines"))
  2534.         ps = LINES;
  2535.     else if (almost_equals(c_token,"i$mpulses"))
  2536.         ps = IMPULSES;
  2537.     else if (almost_equals(c_token,"p$oints"))
  2538.         ps = POINTSTYLE;
  2539.     else if (almost_equals(c_token,"linesp$oints"))
  2540.         ps = LINESPOINTS;
  2541.     else if (almost_equals(c_token,"d$ots"))
  2542.         ps = DOTS;
  2543.         else if (almost_equals(c_token,"ye$rrorbars"))
  2544.                 ps = YERRORBARS;
  2545.     else if (almost_equals(c_token,"e$rrorbars"))
  2546.                 ps = YERRORBARS;
  2547.         else if (almost_equals(c_token,"xe$rrorbars"))
  2548.                 ps = XERRORBARS;
  2549.         else if (almost_equals(c_token,"xye$rrorbars"))
  2550.                 ps = XYERRORBARS;
  2551.         else if (almost_equals(c_token,"boxes"))
  2552.         ps = BOXES;
  2553.     else if (almost_equals(c_token,"boxer$rorbars"))
  2554.         ps = BOXERROR;
  2555.         else if (almost_equals(c_token,"boxx$yerrorbars"))
  2556.                 ps = BOXXYERROR;
  2557.         else if (almost_equals(c_token,"st$eps"))
  2558.         ps = STEPS;
  2559.     else if (almost_equals(c_token,"fs$teps"))
  2560.         ps = FSTEPS;
  2561. else if (almost_equals(c_token,"vec$tor"))
  2562. ps = VECTOR;
  2563.     else {
  2564.         int_error("expecting 'lines', 'points', 'linespoints', 'dots', 'impulses', \n\
  2565.         'yerrorbars', 'xerrorbars', 'xyerrorbars', 'steps', 'fsteps', 'boxes', \n\
  2566.         'boxerrorbars', 'boxxyerrorbars', 'vector'",c_token);
  2567.       return 0; /* keep gcc -Wuninitialised happy */
  2568.    }
  2569.     c_token++;
  2570.     return(ps);
  2571. }
  2572.  
  2573. /* For set [xy]tics... command*/
  2574. #ifdef ANSI_C
  2575. static void load_tics(int axis, struct ticdef *tdef)
  2576. #else
  2577. static void
  2578. load_tics(axis,tdef)
  2579.     int axis;
  2580.     struct ticdef *tdef;    /* change this ticdef */
  2581. #endif
  2582. {
  2583.     if (equals(c_token,"(")) { /* set : TIC_USER */
  2584.        c_token++;
  2585.        load_tic_user(axis,tdef);
  2586.     } else {                /* series : TIC_SERIES */
  2587.        load_tic_series(axis,tdef);
  2588.     }
  2589. }
  2590.  
  2591. /* load TIC_USER definition */
  2592. /* (tic[,tic]...)
  2593.  * where tic is ["string"] value
  2594.  * Left paren is already scanned off before entry.
  2595.  */
  2596. static void
  2597. load_tic_user(axis,tdef)
  2598.     int axis;
  2599.     struct ticdef *tdef;
  2600. {
  2601.     struct ticmark *list = NULL; /* start of list */
  2602.     struct ticmark *last = NULL; /* end of list */
  2603.     struct ticmark *tic = NULL; /* new ticmark */
  2604.     char temp_string[MAX_LINE_LEN];
  2605.  
  2606.     while (!END_OF_COMMAND) {
  2607.        /* parse a new ticmark */
  2608.        tic = (struct ticmark *)alloc((unsigned long)sizeof(struct ticmark), (char *)NULL);
  2609.        if (tic == (struct ticmark *)NULL) {
  2610.           free_marklist(list);
  2611.           int_error("out of memory for tic mark", c_token);
  2612.        }
  2613.  
  2614.        /* has a string with it? */
  2615.        if (isstring(c_token)) {
  2616.           quote_str(temp_string,c_token, MAX_LINE_LEN);
  2617.           tic->label = alloc((unsigned long)strlen(temp_string)+1, "tic label");
  2618.           (void) strcpy(tic->label, temp_string);
  2619.           c_token++;
  2620.        } else
  2621.         tic->label = NULL;
  2622.  
  2623.        /* in any case get the value */
  2624.         GET_NUM_OR_TIME(tic->position, axis);
  2625.        tic->next = NULL;
  2626.  
  2627.        /* append to list */
  2628.        if (list == NULL)
  2629.         last = list = tic;    /* new list */
  2630.        else {                /* append to list */
  2631.           last->next = tic;
  2632.           last = tic;
  2633.        }
  2634.  
  2635.        /* expect "," or ")" here */
  2636.        if (!END_OF_COMMAND && equals(c_token, ","))
  2637.         c_token++;        /* loop again */
  2638.        else
  2639.         break;            /* hopefully ")" */
  2640.     }
  2641.     
  2642.     if (END_OF_COMMAND || !equals(c_token, ")")) {
  2643.        free_marklist(list);
  2644.        int_error("expecting right parenthesis )", c_token);
  2645.     }
  2646.     c_token++;
  2647.     
  2648.     /* successful list */
  2649.     if (tdef->type == TIC_USER) {
  2650.        /* remove old list */
  2651.         /* VAX Optimiser was stuffing up following line. Turn Optimiser OFF */
  2652.        free_marklist(tdef->def.user);
  2653.        tdef->def.user = NULL;
  2654.     }
  2655.     tdef->type = TIC_USER;
  2656.     tdef->def.user = list;
  2657. }
  2658.  
  2659. static void
  2660. free_marklist(list)
  2661.     struct ticmark *list;
  2662. {
  2663.     register struct ticmark *freeable;
  2664.  
  2665.     while (list != NULL) {
  2666.        freeable = list;
  2667.        list = list->next;
  2668.        if (freeable->label != NULL)
  2669.         free( (char *)freeable->label );
  2670.        free( (char *)freeable );
  2671.     }
  2672. }
  2673.  
  2674. /* load TIC_SERIES definition */
  2675. /* [start,]incr[,end] */
  2676. static void
  2677. load_tic_series(axis,tdef)
  2678.     int axis;
  2679.     struct ticdef *tdef;
  2680. {
  2681.   double start, incr, end;
  2682.   int incr_token;
  2683.  
  2684.   GET_NUM_OR_TIME(start,axis);
  2685.  
  2686.   if (!equals(c_token, ",")) {
  2687.         /* only step specified */
  2688.         incr = start;
  2689.         start = -VERYLARGE;
  2690.         end = VERYLARGE;
  2691.   } else {
  2692.  
  2693.     c_token++;
  2694.  
  2695.     incr_token = c_token;
  2696.      GET_NUM_OR_TIME(incr, axis);
  2697.  
  2698.     if (END_OF_COMMAND)
  2699.      end = VERYLARGE;
  2700.     else {
  2701.        if (!equals(c_token, ","))
  2702.         int_error("expecting comma to separate incr,end", c_token);
  2703.        c_token++;
  2704.         GET_NUM_OR_TIME(end, axis);
  2705.     }
  2706.     if (!END_OF_COMMAND)
  2707.      int_error("tic series is defined by [start,]increment[,end]", 
  2708.              c_token);
  2709.     
  2710.     if (start < end && incr <= 0)
  2711.      int_error("increment must be positive", incr_token);
  2712.     if (start > end && incr >= 0)
  2713.      int_error("increment must be negative", incr_token);
  2714.     if (start > end) {
  2715.        /* put in order */
  2716.         double numtics;
  2717.         numtics = floor( (end*(1+SIGNIF) - start)/incr );
  2718.         end = start;
  2719.         start = end + numtics*incr;
  2720.         incr = -incr;
  2721. /*
  2722.        double temp = start;
  2723.        start = end;
  2724.        end = temp;
  2725.        incr = -incr;
  2726.  */
  2727.     }
  2728.   }
  2729.  
  2730.     if (tdef->type == TIC_USER) {
  2731.        /* remove old list */
  2732.         /* VAX Optimiser was stuffing up following line. Turn Optimiser OFF */
  2733.        free_marklist(tdef->def.user);
  2734.        tdef->def.user = NULL;
  2735.     }
  2736.     tdef->type = TIC_SERIES;
  2737.     tdef->def.series.start = start;
  2738.     tdef->def.series.incr = incr;
  2739.     tdef->def.series.end = end;
  2740. }
  2741.  
  2742. static void
  2743. load_offsets (a, b, c, d)
  2744. double *a,*b, *c, *d;
  2745. {
  2746. struct value t;
  2747.  
  2748.     *a = real (const_express(&t));  /* loff value */
  2749.     if (!equals(c_token,","))
  2750.         return;
  2751.  
  2752.     c_token++;
  2753.     *b = real (const_express(&t));  /* roff value */
  2754.     if (!equals(c_token,","))
  2755.         return;
  2756.  
  2757.     c_token++;
  2758.     *c = real (const_express(&t));  /* toff value */
  2759.     if (!equals(c_token,","))
  2760.         return;
  2761.  
  2762.     c_token++;
  2763.     *d = real (const_express(&t));  /* boff value */
  2764. }
  2765.  
  2766. TBOOLEAN                /* new value for autosc */
  2767. load_range(axis,a,b,autosc)        /* also used by command.c */
  2768. int axis;
  2769. double *a,*b;
  2770. TBOOLEAN autosc;
  2771. {
  2772.     if (equals(c_token,"]"))
  2773.         return(autosc);
  2774.     if (END_OF_COMMAND) {
  2775.         int_error("starting range value or ':' or 'to' expected",c_token);
  2776.     } else if (!equals(c_token,"to") && !equals(c_token,":"))  {
  2777.         if (equals(c_token,"*")) {
  2778.             autosc |= 1;
  2779.             c_token++;
  2780.         } else {
  2781.             GET_NUM_OR_TIME(*a, axis);
  2782.             autosc &= 2;
  2783.         }
  2784.     }    
  2785.     if (!equals(c_token,"to") && !equals(c_token,":"))
  2786.         int_error("':' or keyword 'to' expected",c_token);
  2787.     c_token++;
  2788.     if (!equals(c_token,"]")) {
  2789.         if (equals(c_token,"*")) {
  2790.             autosc |= 2;
  2791.             c_token++;
  2792.         } else {
  2793.             GET_NUM_OR_TIME(*b, axis);
  2794.             autosc &= 1;
  2795.         }
  2796.     }
  2797.      return(autosc);
  2798. }
  2799.  
  2800. /* return 1 if format looks like a numeric format
  2801.  * ie more than one %{efg}, or %something-else
  2802.  */ 
  2803.  
  2804. static int looks_like_numeric(format)
  2805. char *format;
  2806. {
  2807.     if (!(format=strchr(format,'%'))) return 0;
  2808.     
  2809.     while ( ++format, (*format >= '0' && *format <= '9') || *format=='.')
  2810.         ;
  2811.  
  2812.     return ( *format == 'f' || *format == 'g' || *format == 'e' );
  2813. }
  2814.  
  2815.  
  2816. /* parse a position of the form
  2817.  *    [coords] x, [coords] y {,[coords] z}
  2818.  * where coords is one of first,second.graph,screen
  2819.  * if first or second, we need to take datatype into account
  2820.  * mixed co-ordinates are for specialists, but it's not particularly
  2821.  * hard to implement...
  2822.  */
  2823.  
  2824. #define GET_NUMBER_OR_TIME(store,axes,axis) \
  2825. do{if (axes>=0 && datatype[axes+axis] == TIME && isstring(c_token) ) { \
  2826.     char ss[80]; struct tm tm; \
  2827.     quote_str(ss,c_token, 80); ++c_token; \
  2828.     if (gstrptime(ss,timefmt,&tm)) store = (double) gtimegm(&tm); \
  2829.    } else {\
  2830.     struct value value; \
  2831.     store = real(const_express(&value));\
  2832.   }}while(0)
  2833.  
  2834.  
  2835.  
  2836. static void get_position_type(type, axes)
  2837. enum position_type *type;
  2838. int *axes;
  2839.     if (almost_equals(c_token, "fir$st")) {
  2840.         ++c_token;
  2841.         *type=first_axes;
  2842.     } else if (almost_equals(c_token, "sec$ond")) {
  2843.         ++c_token;
  2844.         *type=second_axes;
  2845.     } else if (almost_equals(c_token, "gr$aph")) {
  2846.         ++c_token;
  2847.         *type=graph;
  2848.     } else if (almost_equals(c_token, "sc$reen")) {
  2849.         ++c_token;
  2850.         *type=screen;
  2851.     }
  2852.  
  2853.     switch(*type) {
  2854.         case first_axes: *axes=FIRST_AXES; return;
  2855.         case second_axes: *axes=SECOND_AXES; return;
  2856.         default: *axes = (-1); return;
  2857.     }
  2858. }
  2859.  
  2860. static enum position_type get_position(pos,type)
  2861. struct position *pos;
  2862. enum position_type type;
  2863. {
  2864.     int axes;
  2865.  
  2866.     get_position_type(&type, &axes);
  2867.     pos->scalex = type;
  2868.     GET_NUMBER_OR_TIME(pos->x, axes, FIRST_X_AXIS);
  2869.     if (!equals(c_token++, ","))
  2870.         int_error("Expected comma", c_token);
  2871.  
  2872.     get_position_type(&type, &axes);
  2873.     pos->scaley = type;
  2874.     GET_NUMBER_OR_TIME(pos->y, axes, FIRST_Y_AXIS);
  2875.  
  2876.     /* z is not really allowed for a screen co-ordinate, but keep it simple ! */
  2877.     if (equals(c_token, ",")) {
  2878.         ++c_token;
  2879.         get_position_type(&type, &axes);
  2880.         pos->scalez = type;
  2881.         GET_NUMBER_OR_TIME(pos->z, axes, FIRST_Z_AXIS);
  2882.     }
  2883.     else {
  2884.         pos->z=0;
  2885.         pos->scalez = type; /* same as y */
  2886.     }
  2887.  
  2888.     return type; /* so co-ordinates can propagate */
  2889. }
  2890.  
  2891. static void set_locale(lcl)
  2892. char *lcl;
  2893. {
  2894.     int i;
  2895.  
  2896. #ifdef HAVE_LOCALE
  2897.     if (setlocale(LC_TIME, lcl))
  2898.         strcpy(cur_locale, lcl);
  2899.     else
  2900.         int_error("Locale not available", c_token);
  2901.  
  2902.     /* we can do a *lot* better than this ; eg use system functions
  2903.      * where available; create values on first use, etc
  2904.      */
  2905.      
  2906.     for (i=0; i<7; ++i)
  2907.     {
  2908.         struct tm tm;
  2909.         tm.tm_wday = i;  /* hope this enough */
  2910.         strftime(full_day_names[i], sizeof(full_day_names[i]), "%a", &tm);
  2911.         strftime(abbrev_day_names[i], sizeof(abbrev_day_names[i]), "%A", &tm);
  2912.     }
  2913.     for (i=0; i<12; ++i)
  2914.     {
  2915.         struct tm tm;
  2916.         tm.tm_mon = i;  /* hope this enough */
  2917.         strftime(full_day_names[i], sizeof(full_day_names[i]), "%b", &tm);
  2918.         strftime(abbrev_day_names[i], sizeof(abbrev_day_names[i]), "%B", &tm);
  2919.     }
  2920. #else
  2921.     strcpy(cur_locale, lcl);
  2922. #endif /* HAVE_LOCALE */
  2923. }
  2924.